diff options
Diffstat (limited to 'src/pulsecore')
195 files changed, 1565 insertions, 839 deletions
diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c index eba1c2cb..5c7af2a8 100644 --- a/src/pulsecore/asyncmsgq.c +++ b/src/pulsecore/asyncmsgq.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/asyncmsgq.h b/src/pulsecore/asyncmsgq.h index 93f1ce86..1f38207a 100644 --- a/src/pulsecore/asyncmsgq.h +++ b/src/pulsecore/asyncmsgq.h @@ -1,8 +1,6 @@ #ifndef foopulseasyncmsgqhfoo #define foopulseasyncmsgqhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/asyncq.c b/src/pulsecore/asyncq.c index 8e0dfbc3..03e9f0df 100644 --- a/src/pulsecore/asyncq.c +++ b/src/pulsecore/asyncq.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/asyncq.h b/src/pulsecore/asyncq.h index 4cdf8cd0..e6847ab8 100644 --- a/src/pulsecore/asyncq.h +++ b/src/pulsecore/asyncq.h @@ -1,8 +1,6 @@ #ifndef foopulseasyncqhfoo #define foopulseasyncqhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h index ad3dca30..a91c4d56 100644 --- a/src/pulsecore/atomic.h +++ b/src/pulsecore/atomic.h @@ -1,12 +1,11 @@ #ifndef foopulseatomichfoo #define foopulseatomichfoo -/* $Id$ */ - /*** This file is part of PulseAudio. - Copyright 2006 Lennart Poettering + Copyright 2006-2008 Lennart Poettering + Copyright 2008 Nokia Corporation PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -380,9 +379,9 @@ static inline int pa_atomic_dec(pa_atomic_t *a) { /* Returns non-zero when the operation was successful. */ static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { - int failed = 1; + pa_bool_t failed; do { - failed = __kernel_cmpxchg(old_i, new_i, &a->value); + failed = !!__kernel_cmpxchg(old_i, new_i, &a->value); } while(failed && a->value == old_i); return !failed; } @@ -404,10 +403,10 @@ static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) { } static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { - int failed = 1; + pa_bool_t failed; do { - failed = __kernel_cmpxchg_u((unsigned long) old_p, (unsigned long) new_p, &a->value); - } while(failed && a->value == old_p); + failed = !!__kernel_cmpxchg_u((unsigned long) old_p, (unsigned long) new_p, &a->value); + } while(failed && a->value == (unsigned long) old_p); return !failed; } diff --git a/src/pulsecore/authkey-prop.c b/src/pulsecore/authkey-prop.c index 54154500..a953bf7d 100644 --- a/src/pulsecore/authkey-prop.c +++ b/src/pulsecore/authkey-prop.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/authkey-prop.h b/src/pulsecore/authkey-prop.h index 247202f3..de02d2aa 100644 --- a/src/pulsecore/authkey-prop.h +++ b/src/pulsecore/authkey-prop.h @@ -1,8 +1,6 @@ #ifndef fooauthkeyprophfoo #define fooauthkeyprophfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c index 80bc8576..f3f40f80 100644 --- a/src/pulsecore/authkey.c +++ b/src/pulsecore/authkey.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/authkey.h b/src/pulsecore/authkey.h index 18e5157d..8301db1e 100644 --- a/src/pulsecore/authkey.h +++ b/src/pulsecore/authkey.h @@ -1,8 +1,6 @@ #ifndef fooauthkeyhfoo #define fooauthkeyhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/autoload.c b/src/pulsecore/autoload.c index a1d3e02d..26c294b2 100644 --- a/src/pulsecore/autoload.c +++ b/src/pulsecore/autoload.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/autoload.h b/src/pulsecore/autoload.h index 8a3522a7..3926351f 100644 --- a/src/pulsecore/autoload.h +++ b/src/pulsecore/autoload.h @@ -1,8 +1,6 @@ #ifndef fooautoloadhfoo #define fooautoloadhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/avahi-wrap.c b/src/pulsecore/avahi-wrap.c index fae54810..d5f40d83 100644 --- a/src/pulsecore/avahi-wrap.c +++ b/src/pulsecore/avahi-wrap.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/avahi-wrap.h b/src/pulsecore/avahi-wrap.h index 1e20ec38..7d8995bb 100644 --- a/src/pulsecore/avahi-wrap.h +++ b/src/pulsecore/avahi-wrap.h @@ -1,8 +1,6 @@ #ifndef fooavahiwrapperhfoo #define fooavahiwrapperhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 925a2e8c..cbdb602a 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/cli-command.h b/src/pulsecore/cli-command.h index 2a923443..9bf35dc3 100644 --- a/src/pulsecore/cli-command.h +++ b/src/pulsecore/cli-command.h @@ -1,8 +1,6 @@ #ifndef fooclicommandhfoo #define fooclicommandhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index 029a7089..c92fca20 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -118,6 +116,9 @@ char *pa_sink_list_to_string(pa_core *c) { for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t; + pa_usec_t min_latency, max_latency; + + pa_sink_get_latency_range(sink, &min_latency, &max_latency); pa_strbuf_printf( s, @@ -130,6 +131,8 @@ char *pa_sink_list_to_string(pa_core *c) { "\tmuted: %s\n" "\tcurrent latency: %0.2f ms\n" "\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n" + "\tmax request: %lu KiB\n" + "\tmax rewind: %lu KiB\n" "\tmonitor source: %u\n" "\tsample spec: %s\n" "\tchannel map: %s\n" @@ -149,7 +152,9 @@ char *pa_sink_list_to_string(pa_core *c) { 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) sink->min_latency / PA_USEC_PER_MSEC, (double) sink->max_latency / 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, + (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, pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map), @@ -186,6 +191,9 @@ char *pa_source_list_to_string(pa_core *c) { for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], *t; + pa_usec_t min_latency, max_latency; + + pa_source_get_latency_range(source, &min_latency, &max_latency); pa_strbuf_printf( s, @@ -198,6 +206,7 @@ char *pa_source_list_to_string(pa_core *c) { "\tmuted: %s\n" "\tcurrent latency: %0.2f ms\n" "\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n" + "\tmax rewind: %lu KiB\n" "\tsample spec: %s\n" "\tchannel map: %s\n" "\tused by: %u\n" @@ -216,7 +225,8 @@ char *pa_source_list_to_string(pa_core *c) { pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source)), pa_yes_no(pa_source_get_mute(source)), (double) pa_source_get_latency(source) / PA_USEC_PER_MSEC, - (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC, (double) source->min_latency / PA_USEC_PER_MSEC, (double) source->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), pa_source_used_by(source), @@ -287,7 +297,7 @@ char *pa_source_output_list_to_string(pa_core *c) { o->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "", state_table[pa_source_output_get_state(o)], o->source->index, o->source->name, - (double) pa_source_output_get_latency(o) / PA_USEC_PER_MSEC, + (double) pa_source_output_get_latency(o, NULL) / PA_USEC_PER_MSEC, clt, pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map), @@ -296,6 +306,8 @@ char *pa_source_output_list_to_string(pa_core *c) { pa_strbuf_printf(s, "\towner module: %u\n", o->module->index); if (o->client) pa_strbuf_printf(s, "\tclient: %u <%s>\n", o->client->index, pa_strnull(pa_proplist_gets(o->client->proplist, PA_PROP_APPLICATION_NAME))); + if (o->direct_on_input) + pa_strbuf_printf(s, "\tdirect on input: %u\n", o->direct_on_input->index); t = pa_proplist_to_string(o->proplist); pa_strbuf_printf(s, "\tproperties:\n%s", t); @@ -361,7 +373,7 @@ char *pa_sink_input_list_to_string(pa_core *c) { i->sink->index, i->sink->name, pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), pa_yes_no(pa_sink_input_get_mute(i)), - (double) pa_sink_input_get_latency(i) / PA_USEC_PER_MSEC, + (double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC, clt, pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), diff --git a/src/pulsecore/cli-text.h b/src/pulsecore/cli-text.h index 9e5bf081..f4cb97a5 100644 --- a/src/pulsecore/cli-text.h +++ b/src/pulsecore/cli-text.h @@ -1,8 +1,6 @@ #ifndef fooclitexthfoo #define fooclitexthfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c index 47712d30..b3c639f8 100644 --- a/src/pulsecore/cli.c +++ b/src/pulsecore/cli.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/cli.h b/src/pulsecore/cli.h index 2b58d458..6077a8e8 100644 --- a/src/pulsecore/cli.h +++ b/src/pulsecore/cli.h @@ -1,8 +1,6 @@ #ifndef fooclihfoo #define fooclihfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/client.c b/src/pulsecore/client.c index 4eca4e2a..0ffd2330 100644 --- a/src/pulsecore/client.c +++ b/src/pulsecore/client.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -66,18 +64,21 @@ pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) { } void pa_client_free(pa_client *c) { + pa_core *core; + pa_assert(c); pa_assert(c->core); + core = c->core; pa_idxset_remove_by_data(c->core->clients, c, NULL); - pa_core_check_quit(c->core); - pa_log_info("Freed %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME))); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_proplist_free(c->proplist); pa_xfree(c->driver); pa_xfree(c); + + pa_core_check_quit(core); } void pa_client_kill(pa_client *c) { diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h index bff057ed..28d1fe5f 100644 --- a/src/pulsecore/client.h +++ b/src/pulsecore/client.h @@ -1,8 +1,6 @@ #ifndef foopulseclienthfoo #define foopulseclienthfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index 12ea49c2..4aec45d7 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h index b56d979e..7eb1fae2 100644 --- a/src/pulsecore/conf-parser.h +++ b/src/pulsecore/conf-parser.h @@ -1,8 +1,6 @@ #ifndef fooconfparserhfoo #define fooconfparserhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/core-error.c b/src/pulsecore/core-error.c index 8a61e726..3d6c2c3b 100644 --- a/src/pulsecore/core-error.c +++ b/src/pulsecore/core-error.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/core-error.h b/src/pulsecore/core-error.h index 443c4883..b0c306c7 100644 --- a/src/pulsecore/core-error.h +++ b/src/pulsecore/core-error.h @@ -1,8 +1,6 @@ #ifndef foocoreerrorhfoo #define foocoreerrorhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c index e5546007..75fa2ff1 100644 --- a/src/pulsecore/core-scache.c +++ b/src/pulsecore/core-scache.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -63,7 +61,7 @@ #include "core-scache.h" -#define UNLOAD_POLL_TIME 5 +#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) { pa_core *c = userdata; @@ -131,8 +129,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { } e->last_used_time = 0; - e->memchunk.memblock = NULL; - e->memchunk.index = e->memchunk.length = 0; + pa_memchunk_reset(&e->memchunk); e->filename = NULL; e->lazy = FALSE; e->last_used_time = 0; @@ -165,8 +162,7 @@ int pa_scache_add_item( pa_assert(!map || (pa_channel_map_valid(map) && ss && ss->channels == map->channels)); if (ss && !map) - if (!(map = pa_channel_map_init_auto(&tmap, ss->channels, PA_CHANNEL_MAP_DEFAULT))) - return -1; + pa_channel_map_init_extend(&tmap, ss->channels, PA_CHANNEL_MAP_DEFAULT); if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX) return -1; @@ -277,8 +273,7 @@ int pa_scache_remove_item(pa_core *c, const char *name) { if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) return -1; - if (pa_idxset_remove_by_data(c->scache, e, NULL) != e) - pa_assert(0); + pa_assert_se(pa_idxset_remove_by_data(c->scache, e, NULL) == e); pa_log_debug("Removed sample \"%s\"", name); diff --git a/src/pulsecore/core-scache.h b/src/pulsecore/core-scache.h index 31f3ff32..80e0fd04 100644 --- a/src/pulsecore/core-scache.h +++ b/src/pulsecore/core-scache.h @@ -1,8 +1,6 @@ #ifndef foocorescachehfoo #define foocorescachehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c index 06c5a4ad..6107002b 100644 --- a/src/pulsecore/core-subscribe.c +++ b/src/pulsecore/core-subscribe.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/core-subscribe.h b/src/pulsecore/core-subscribe.h index 2b6863f9..2f9730d9 100644 --- a/src/pulsecore/core-subscribe.h +++ b/src/pulsecore/core-subscribe.h @@ -1,8 +1,6 @@ #ifndef foocoresubscribehfoo #define foocoresubscribehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index c8ea4f52..d259fb16 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -1144,12 +1142,13 @@ fail: /* Unlock a temporary lcok file */ int pa_unlock_lockfile(const char *fn, int fd) { int r = 0; - pa_assert(fn); pa_assert(fd >= 0); - if (unlink(fn) < 0) { - pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno)); - r = -1; + if (fn) { + if (unlink(fn) < 0) { + pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno)); + r = -1; + } } if (pa_lock_fd(fd, 0) < 0) { @@ -1165,24 +1164,35 @@ int pa_unlock_lockfile(const char *fn, int fd) { return r; } -char *pa_get_runtime_dir(void) { +static char *get_dir(mode_t m, const char *env_name) { const char *e; char *d; - if ((e = getenv("PULSE_RUNTIME_PATH"))) + if ((e = getenv(env_name))) d = pa_xstrdup(e); else { char h[PATH_MAX]; + struct stat st; if (!pa_get_home_dir(h, sizeof(h))) { pa_log_error("Failed to get home directory."); return NULL; } + if (stat(h, &st) < 0) { + pa_log_error("Failed to stat home directory %s: %s", h, pa_cstrerror(errno)); + return NULL; + } + + if (st.st_uid != getuid()) { + pa_log_error("Home directory %s not ours.", d); + return NULL; + } + d = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h); } - if (pa_make_secure_dir(d, 0700, (pid_t) -1, (pid_t) -1) < 0) { + if (pa_make_secure_dir(d, m, (pid_t) -1, (pid_t) -1) < 0) { pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno)); return NULL; } @@ -1190,6 +1200,14 @@ char *pa_get_runtime_dir(void) { return d; } +char *pa_get_runtime_dir(void) { + return get_dir(pa_in_system_mode() ? 0755 : 0700, "PULSE_RUNTIME_PATH"); +} + +char *pa_get_state_dir(void) { + return get_dir(0700, "PULSE_STATE_PATH"); +} + /* Try to open a configuration file. If "env" is specified, open the * value of the specified environment variable. Otherwise look for a * file "local" in the home directory or a file "global" in global @@ -1418,7 +1436,7 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { } /* Returns nonzero when *s starts with *pfx */ -int pa_startswith(const char *s, const char *pfx) { +pa_bool_t pa_startswith(const char *s, const char *pfx) { size_t l; pa_assert(s); @@ -1430,7 +1448,7 @@ int pa_startswith(const char *s, const char *pfx) { } /* Returns nonzero when *s ends with *sfx */ -int pa_endswith(const char *s, const char *sfx) { +pa_bool_t pa_endswith(const char *s, const char *sfx) { size_t l1, l2; pa_assert(s); @@ -1472,13 +1490,16 @@ char *pa_make_path_absolute(const char *p) { /* if fn is null return the PulseAudio run time path in s (~/.pulse) * if fn is non-null and starts with / return fn * otherwise append fn to the run time path and return it */ -char *pa_runtime_path(const char *fn) { +static char *get_path(const char *fn, pa_bool_t rt) { char *rtp; if (pa_is_path_absolute(fn)) return pa_xstrdup(fn); - rtp = pa_get_runtime_dir(); + rtp = rt ? pa_get_runtime_dir() : pa_get_state_dir(); + + if (!rtp) + return NULL; if (fn) { char *r; @@ -1489,6 +1510,14 @@ char *pa_runtime_path(const char *fn) { return rtp; } +char *pa_runtime_path(const char *fn) { + return get_path(fn, 1); +} + +char *pa_state_path(const char *fn) { + return get_path(fn, 0); +} + /* Convert the string s to a signed integer in *ret_i */ int pa_atoi(const char *s, int32_t *ret_i) { char *x = NULL; @@ -1541,13 +1570,13 @@ static void c_locale_destroy(void) { } #endif -int pa_atof(const char *s, float *ret_f) { +int pa_atod(const char *s, double *ret_d) { char *x = NULL; - float f; + double f; int r = 0; pa_assert(s); - pa_assert(ret_f); + pa_assert(ret_d); /* This should be locale independent */ @@ -1562,22 +1591,18 @@ int pa_atof(const char *s, float *ret_f) { if (c_locale) { errno = 0; - f = strtof_l(s, &x, c_locale); + f = strtod_l(s, &x, c_locale); } else #endif { errno = 0; -#ifdef HAVE_STRTOF - f = strtof(s, &x); -#else f = strtod(s, &x); -#endif } if (!x || *x || errno != 0) r = -1; else - *ret_f = f; + *ret_d = f; return r; } @@ -1774,10 +1799,11 @@ int pa_close_all(int except_fd, ...) { i = 0; if (except_fd >= 0) { + int fd; p[i++] = except_fd; - while ((p[i++] = va_arg(ap, int)) >= 0) - ; + while ((fd = va_arg(ap, int)) >= 0) + p[i++] = fd; } p[i] = -1; @@ -1803,6 +1829,7 @@ int pa_close_allv(const int except_fds[]) { struct dirent *de; while ((de = readdir(d))) { + pa_bool_t found; long l; char *e = NULL; int i; @@ -1826,17 +1853,23 @@ int pa_close_allv(const int except_fds[]) { return -1; } - if (fd <= 3) + if (fd < 3) continue; if (fd == dirfd(d)) continue; + found = FALSE; for (i = 0; except_fds[i] >= 0; i++) - if (except_fds[i] == fd) - continue; + if (except_fds[i] == fd) { + found = TRUE; + break; + } + + if (found) + continue; - if (close(fd) < 0) { + if (pa_close(fd) < 0) { saved_errno = errno; closedir(d); errno = saved_errno; @@ -1890,10 +1923,11 @@ int pa_unblock_sigs(int except, ...) { i = 0; if (except >= 1) { + int sig; p[i++] = except; - while ((p[i++] = va_arg(ap, int)) >= 0) - ; + while ((sig = va_arg(ap, int)) >= 0) + p[i++] = sig; } p[i] = -1; @@ -1957,12 +1991,12 @@ int pa_reset_sigsv(const int except[]) { int sig; for (sig = 1; sig < _NSIG; sig++) { - int reset = 1; + pa_bool_t reset = TRUE; switch (sig) { case SIGKILL: case SIGSTOP: - reset = 0; + reset = FALSE; break; default: { @@ -1970,7 +2004,7 @@ int pa_reset_sigsv(const int except[]) { for (i = 0; except[i] > 0; i++) { if (sig == except[i]) { - reset = 0; + reset = FALSE; break; } } @@ -2000,3 +2034,12 @@ void pa_set_env(const char *key, const char *value) { putenv(pa_sprintf_malloc("%s=%s", key, value)); } + +pa_bool_t pa_in_system_mode(void) { + const char *e; + + if (!(e = getenv("PULSE_SYSTEM"))) + return FALSE; + + return !!atoi(e); +} diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index ec4cdc43..2ed81fc5 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -1,8 +1,6 @@ #ifndef foocoreutilhfoo #define foocoreutilhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -114,18 +112,20 @@ int pa_unlock_lockfile(const char *fn, int fd); char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength); -int pa_startswith(const char *s, const char *pfx) PA_GCC_PURE; -int pa_endswith(const char *s, const char *sfx) PA_GCC_PURE; +pa_bool_t pa_startswith(const char *s, const char *pfx) PA_GCC_PURE; +pa_bool_t pa_endswith(const char *s, const char *sfx) PA_GCC_PURE; FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result); char* pa_find_config_file(const char *global, const char *local, const char *env); char *pa_get_runtime_dir(void); +char *pa_get_state_dir(void); char *pa_runtime_path(const char *fn); +char *pa_state_path(const char *fn); int pa_atoi(const char *s, int32_t *ret_i); int pa_atou(const char *s, uint32_t *ret_u); -int pa_atof(const char *s, float *ret_f); +int pa_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); @@ -180,4 +180,8 @@ int pa_reset_sigsv(const int except[]); void pa_set_env(const char *key, const char *value); +pa_bool_t pa_in_system_mode(void); + +#define pa_streq(a,b) (!strcmp((a),(b))) + #endif diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 3b758a38..b2638b10 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -135,7 +133,6 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3; - c->is_system_instance = FALSE; c->disallow_module_loading = FALSE; c->realtime_scheduling = FALSE; c->realtime_priority = 5; @@ -210,11 +207,16 @@ static void quit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED con void pa_core_check_quit(pa_core *c) { pa_assert(c); - if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_size(c->clients) == 0) { + if (!c->quit_event && + c->exit_idle_time >= 0 && + pa_idxset_size(c->clients) == 0) { + struct timeval tv; pa_gettimeofday(&tv); tv.tv_sec+= c->exit_idle_time; + c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c); + } else if (c->quit_event && pa_idxset_size(c->clients) > 0) { c->mainloop->time_free(c->quit_event); c->quit_event = NULL; diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 50c05b4c..d9ed46f6 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -1,8 +1,6 @@ #ifndef foocorehfoo #define foocorehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -123,7 +121,6 @@ struct pa_core { pa_bool_t disallow_module_loading, running_as_daemon; pa_resample_method_t resample_method; - pa_bool_t is_system_instance; pa_bool_t realtime_scheduling; int realtime_priority; pa_bool_t disable_remixing; diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h index 51dfc33d..c15c469b 100644 --- a/src/pulsecore/creds.h +++ b/src/pulsecore/creds.h @@ -1,8 +1,6 @@ #ifndef foocredshfoo #define foocredshfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/dllmain.c b/src/pulsecore/dllmain.c index 52cbf9e2..269de604 100644 --- a/src/pulsecore/dllmain.c +++ b/src/pulsecore/dllmain.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/dynarray.c b/src/pulsecore/dynarray.c index 8bdb46fa..a1fcd8a3 100644 --- a/src/pulsecore/dynarray.c +++ b/src/pulsecore/dynarray.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/dynarray.h b/src/pulsecore/dynarray.h index 0f222e10..82b42082 100644 --- a/src/pulsecore/dynarray.h +++ b/src/pulsecore/dynarray.h @@ -1,8 +1,6 @@ #ifndef foodynarrayhfoo #define foodynarrayhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/endianmacros.h b/src/pulsecore/endianmacros.h index 6b80246b..26336918 100644 --- a/src/pulsecore/endianmacros.h +++ b/src/pulsecore/endianmacros.h @@ -1,8 +1,6 @@ #ifndef fooendianmacroshfoo #define fooendianmacroshfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/envelope.c b/src/pulsecore/envelope.c index 2f5da5a0..e2691611 100644 --- a/src/pulsecore/envelope.c +++ b/src/pulsecore/envelope.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/envelope.h b/src/pulsecore/envelope.h index c54c137a..5296415a 100644 --- a/src/pulsecore/envelope.h +++ b/src/pulsecore/envelope.h @@ -1,8 +1,6 @@ #ifndef foopulseenvelopehfoo #define foopulseenvelopehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/esound.h b/src/pulsecore/esound.h index ea6a5665..79322ae4 100644 --- a/src/pulsecore/esound.h +++ b/src/pulsecore/esound.h @@ -1,8 +1,6 @@ #ifndef fooesoundhfoo #define fooesoundhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/fdsem.c b/src/pulsecore/fdsem.c index 22d2a850..1531e3db 100644 --- a/src/pulsecore/fdsem.c +++ b/src/pulsecore/fdsem.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/fdsem.h b/src/pulsecore/fdsem.h index f4f7b99a..48a77c49 100644 --- a/src/pulsecore/fdsem.h +++ b/src/pulsecore/fdsem.h @@ -1,8 +1,6 @@ #ifndef foopulsefdsemhfoo #define foopulsefdsemhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c index d9740777..f166ee33 100644 --- a/src/pulsecore/flist.c +++ b/src/pulsecore/flist.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/flist.h b/src/pulsecore/flist.h index 3d9a89a2..c040667d 100644 --- a/src/pulsecore/flist.h +++ b/src/pulsecore/flist.h @@ -1,8 +1,6 @@ #ifndef foopulseflisthfoo #define foopulseflisthfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c index c9d5632c..b7f4109b 100644 --- a/src/pulsecore/hashmap.c +++ b/src/pulsecore/hashmap.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -191,24 +189,36 @@ unsigned pa_hashmap_size(pa_hashmap *h) { } void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) { + struct hashmap_entry *e; + pa_assert(h); pa_assert(state); - if (!*state) - *state = h->first_entry; + if (*state == (void*) -1) + goto at_end; + + if ((!*state && !h->first_entry)) + goto at_end; + + e = *state ? *state : h->first_entry; + + if (e->next) + *state = e->next; else - *state = ((struct hashmap_entry*) *state)->next; + *state = (void*) -1; - if (!*state) { - if (key) - *key = NULL; - return NULL; - } + if (key) + *key = e->key; + + return e->value; + +at_end: + *state = (void *) -1; if (key) - *key = ((struct hashmap_entry*) *state)->key; + *key = NULL; - return ((struct hashmap_entry*) *state)->value; + return NULL; } void* pa_hashmap_steal_first(pa_hashmap *h) { diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h index 98df4502..a4505c4c 100644 --- a/src/pulsecore/hashmap.h +++ b/src/pulsecore/hashmap.h @@ -1,8 +1,6 @@ #ifndef foohashmaphfoo #define foohashmaphfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -51,9 +49,10 @@ unsigned pa_hashmap_size(pa_hashmap *h); /* May be used to iterate through the hashmap. Initially the opaque pointer *state has to be set to NULL. The hashmap may not be - modified during iteration. The key of the entry is returned in - *key, if key is non-NULL. After the last entry in the hashmap NULL - is returned. */ + modified during iteration -- except for deleting the current entry + via pa_hashmap_remove(). The key of the entry is returned in *key, + if key is non-NULL. After the last entry in the hashmap NULL is + returned. */ void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void**key); void *pa_hashmap_steal_first(pa_hashmap *h); diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c index 3a6874c4..0aac4759 100644 --- a/src/pulsecore/hook-list.c +++ b/src/pulsecore/hook-list.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -33,8 +31,7 @@ void pa_hook_init(pa_hook *hook, void *data) { pa_assert(hook); PA_LLIST_HEAD_INIT(pa_hook_slot, hook->slots); - hook->last = NULL; - hook->n_dead = hook->firing = 0; + hook->n_dead = hook->n_firing = 0; hook->data = data; } @@ -42,9 +39,6 @@ static void slot_free(pa_hook *hook, pa_hook_slot *slot) { pa_assert(hook); pa_assert(slot); - if (hook->last == slot) - hook->last = slot->prev; - PA_LLIST_REMOVE(pa_hook_slot, hook->slots, slot); pa_xfree(slot); @@ -52,7 +46,7 @@ static void slot_free(pa_hook *hook, pa_hook_slot *slot) { void pa_hook_free(pa_hook *hook) { pa_assert(hook); - pa_assert(!hook->firing); + pa_assert(hook->n_firing == 0); while (hook->slots) slot_free(hook, hook->slots); @@ -60,19 +54,26 @@ void pa_hook_free(pa_hook *hook) { pa_hook_init(hook, NULL); } -pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *data) { - pa_hook_slot *slot; +pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_priority_t prio, pa_hook_cb_t cb, void *data) { + pa_hook_slot *slot, *where, *prev; pa_assert(cb); slot = pa_xnew(pa_hook_slot, 1); slot->hook = hook; - slot->dead = 0; + slot->dead = FALSE; slot->callback = cb; slot->data = data; + slot->priority = prio; - PA_LLIST_INSERT_AFTER(pa_hook_slot, hook->slots, hook->last, slot); - hook->last = slot; + prev = NULL; + for (where = hook->slots; where; where = where->next) { + if (prio < where->priority) + break; + prev = where; + } + + PA_LLIST_INSERT_AFTER(pa_hook_slot, hook->slots, prev, slot); return slot; } @@ -81,8 +82,8 @@ void pa_hook_slot_free(pa_hook_slot *slot) { pa_assert(slot); pa_assert(!slot->dead); - if (slot->hook->firing > 0) { - slot->dead = 1; + if (slot->hook->n_firing > 0) { + slot->dead = TRUE; slot->hook->n_dead++; } else slot_free(slot->hook, slot); @@ -94,7 +95,7 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { pa_assert(hook); - hook->firing ++; + hook->n_firing ++; for (slot = hook->slots; slot; slot = slot->next) { if (slot->dead) @@ -104,7 +105,8 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { break; } - hook->firing --; + hook->n_firing --; + pa_assert(hook->n_firing >= 0); for (slot = hook->slots; hook->n_dead > 0 && slot; slot = next) { next = slot->next; @@ -115,6 +117,7 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { } } + pa_assert(hook->n_dead == 0); + return result; } - diff --git a/src/pulsecore/hook-list.h b/src/pulsecore/hook-list.h index c288980d..cf85aca5 100644 --- a/src/pulsecore/hook-list.h +++ b/src/pulsecore/hook-list.h @@ -1,8 +1,6 @@ #ifndef foohooklistfoo #define foohooklistfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -38,14 +36,21 @@ typedef enum pa_hook_result { PA_HOOK_CANCEL = -1 } pa_hook_result_t; +typedef enum pa_hook_priority { + PA_HOOK_EARLY = -100, + PA_HOOK_NORMAL = 0, + PA_HOOK_LATE = 100 +} pa_hook_priority_t; + typedef pa_hook_result_t (*pa_hook_cb_t)( void *hook_data, void *call_data, void *slot_data); struct pa_hook_slot { - int dead; + pa_bool_t dead; pa_hook *hook; + pa_hook_priority_t priority; pa_hook_cb_t callback; void *data; PA_LLIST_FIELDS(pa_hook_slot); @@ -53,8 +58,7 @@ struct pa_hook_slot { struct pa_hook { PA_LLIST_HEAD(pa_hook_slot, slots); - pa_hook_slot *last; - int firing, n_dead; + int n_firing, n_dead; void *data; }; @@ -62,7 +66,7 @@ struct pa_hook { void pa_hook_init(pa_hook *hook, void *data); void pa_hook_free(pa_hook *hook); -pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t, void *data); +pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_priority_t prio, pa_hook_cb_t cb, void *data); void pa_hook_slot_free(pa_hook_slot *slot); pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data); diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index 8a88471f..7c9520a4 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/idxset.h b/src/pulsecore/idxset.h index 5b55cec2..0a4e528e 100644 --- a/src/pulsecore/idxset.h +++ b/src/pulsecore/idxset.h @@ -1,8 +1,6 @@ #ifndef fooidxsethfoo #define fooidxsethfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/inet_ntop.c b/src/pulsecore/inet_ntop.c index 4a4f7aac..87551232 100644 --- a/src/pulsecore/inet_ntop.c +++ b/src/pulsecore/inet_ntop.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/inet_pton.c b/src/pulsecore/inet_pton.c index 84d0c0ea..d191e550 100644 --- a/src/pulsecore/inet_pton.c +++ b/src/pulsecore/inet_pton.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c index 63ab2ad7..b40c9815 100644 --- a/src/pulsecore/iochannel.c +++ b/src/pulsecore/iochannel.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -424,3 +422,16 @@ int pa_iochannel_get_send_fd(pa_iochannel *io) { return io->ofd; } + +pa_bool_t pa_iochannel_socket_is_local(pa_iochannel *io) { + pa_assert(io); + + if (pa_socket_is_local(io->ifd)) + return TRUE; + + if (io->ifd != io->ofd) + if (pa_socket_is_local(io->ofd)) + return TRUE; + + return FALSE; +} diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h index c9794d99..9050df90 100644 --- a/src/pulsecore/iochannel.h +++ b/src/pulsecore/iochannel.h @@ -1,8 +1,6 @@ #ifndef fooiochannelhfoo #define fooiochannelhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -85,6 +83,8 @@ void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l); int pa_iochannel_socket_set_rcvbuf(pa_iochannel*io, size_t l); int pa_iochannel_socket_set_sndbuf(pa_iochannel*io, size_t l); +pa_bool_t pa_iochannel_socket_is_local(pa_iochannel *io); + pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io); int pa_iochannel_get_recv_fd(pa_iochannel *io); diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c index 85bbadc4..90afaafd 100644 --- a/src/pulsecore/ioline.c +++ b/src/pulsecore/ioline.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/ioline.h b/src/pulsecore/ioline.h index f4edc7b4..b9a3d9f4 100644 --- a/src/pulsecore/ioline.h +++ b/src/pulsecore/ioline.h @@ -1,8 +1,6 @@ #ifndef fooiolinehfoo #define fooiolinehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c index 9b22e8f5..7b5f865b 100644 --- a/src/pulsecore/ipacl.c +++ b/src/pulsecore/ipacl.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/ipacl.h b/src/pulsecore/ipacl.h index 175f54e0..7b7ffa61 100644 --- a/src/pulsecore/ipacl.h +++ b/src/pulsecore/ipacl.h @@ -1,8 +1,6 @@ #ifndef fooparseaddrhfoo #define fooparseaddrhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/llist.h b/src/pulsecore/llist.h index e62f15b4..46b54eb3 100644 --- a/src/pulsecore/llist.h +++ b/src/pulsecore/llist.h @@ -1,8 +1,6 @@ #ifndef foollistfoo #define foollistfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index b5929ec4..5eda4f65 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h index 765dd2e5..2047696e 100644 --- a/src/pulsecore/log.h +++ b/src/pulsecore/log.h @@ -1,8 +1,6 @@ #ifndef foologhfoo #define foologhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/ltdl-helper.c b/src/pulsecore/ltdl-helper.c index b83897a6..0d4c22f8 100644 --- a/src/pulsecore/ltdl-helper.c +++ b/src/pulsecore/ltdl-helper.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/ltdl-helper.h b/src/pulsecore/ltdl-helper.h index 5c7388a1..ea73de54 100644 --- a/src/pulsecore/ltdl-helper.h +++ b/src/pulsecore/ltdl-helper.h @@ -1,8 +1,6 @@ #ifndef foopulsecoreltdlhelperhfoo #define foopulsecoreltdlhelperhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index 1d9eafd5..fd33b7bb 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -1,8 +1,6 @@ #ifndef foopulsemacrohfoo #define foopulsemacrohfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/mcalign.c b/src/pulsecore/mcalign.c index e12f84f8..a03d5ae7 100644 --- a/src/pulsecore/mcalign.c +++ b/src/pulsecore/mcalign.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/mcalign.h b/src/pulsecore/mcalign.h index 6c8b8d5f..e82eb007 100644 --- a/src/pulsecore/mcalign.h +++ b/src/pulsecore/mcalign.h @@ -1,8 +1,6 @@ #ifndef foomcalignhfoo #define foomcalignhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 7005b441..c2ee1360 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index 8dc3f5a3..efe55b02 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -1,8 +1,6 @@ #ifndef foopulsememblockhfoo #define foopulsememblockhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index c047e56f..a9f28a07 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -786,6 +784,9 @@ void pa_memblockq_set_tlength(pa_memblockq *bq, size_t tlength) { if (bq->tlength > bq->maxlength) bq->tlength = bq->maxlength; + if (bq->prebuf > bq->tlength) + pa_memblockq_set_prebuf(bq, bq->tlength); + if (bq->minreq > bq->tlength) pa_memblockq_set_minreq(bq, bq->tlength); @@ -803,8 +804,8 @@ void pa_memblockq_set_prebuf(pa_memblockq *bq, size_t prebuf) { if (prebuf > 0 && bq->prebuf < bq->base) bq->prebuf = bq->base; - if (bq->prebuf > bq->maxlength) - bq->prebuf = bq->maxlength; + if (bq->prebuf > bq->tlength) + bq->prebuf = bq->tlength; if (bq->prebuf <= 0 || pa_memblockq_get_length(bq) >= bq->prebuf) bq->in_prebuf = FALSE; @@ -908,3 +909,9 @@ unsigned pa_memblockq_get_nblocks(pa_memblockq *bq) { return bq->n_blocks; } + +size_t pa_memblockq_get_base(pa_memblockq *bq) { + pa_assert(bq); + + return bq->base; +} diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h index 7c38757f..81f7cbb8 100644 --- a/src/pulsecore/memblockq.h +++ b/src/pulsecore/memblockq.h @@ -1,8 +1,6 @@ #ifndef foomemblockqhfoo #define foomemblockqhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -169,4 +167,6 @@ pa_bool_t pa_memblockq_prebuf_active(pa_memblockq *bq); unsigned pa_memblockq_get_nblocks(pa_memblockq *bq); +size_t pa_memblockq_get_base(pa_memblockq *bq); + #endif diff --git a/src/pulsecore/memchunk.c b/src/pulsecore/memchunk.c index 16a9c140..0bbf8590 100644 --- a/src/pulsecore/memchunk.c +++ b/src/pulsecore/memchunk.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -49,17 +47,20 @@ pa_memchunk* pa_memchunk_make_writable(pa_memchunk *c, size_t min) { pa_memblock_get_length(c->memblock) >= c->index+min) return c; - l = c->length; - if (l < min) - l = min; + l = PA_MAX(c->length, min); n = pa_memblock_new(pa_memblock_get_pool(c->memblock), l); - tdata = pa_memblock_acquire(n); + sdata = pa_memblock_acquire(c->memblock); + tdata = pa_memblock_acquire(n); + memcpy(tdata, (uint8_t*) sdata + c->index, c->length); - pa_memblock_release(n); + pa_memblock_release(c->memblock); + pa_memblock_release(n); + pa_memblock_unref(c->memblock); + c->memblock = n; c->index = 0; @@ -69,8 +70,7 @@ pa_memchunk* pa_memchunk_make_writable(pa_memchunk *c, size_t min) { pa_memchunk* pa_memchunk_reset(pa_memchunk *c) { pa_assert(c); - c->memblock = NULL; - c->length = c->index = 0; + memset(c, 0, sizeof(*c)); return c; } diff --git a/src/pulsecore/memchunk.h b/src/pulsecore/memchunk.h index 46a82406..9458f4ff 100644 --- a/src/pulsecore/memchunk.h +++ b/src/pulsecore/memchunk.h @@ -1,8 +1,6 @@ #ifndef foomemchunkhfoo #define foomemchunkhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c index 0dab254b..5f5902c9 100644 --- a/src/pulsecore/modargs.c +++ b/src/pulsecore/modargs.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -53,6 +51,12 @@ static int add_key_value(pa_hashmap *map, char *key, char *value, const char* co pa_assert(key); pa_assert(value); + if (pa_hashmap_get(map, key)) { + pa_xfree(key); + pa_xfree(value); + return -1; + } + if (valid_keys) { const char*const* v; for (v = valid_keys; *v; v++) @@ -80,7 +84,15 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); if (args) { - enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state; + enum { + WHITESPACE, + KEY, + VALUE_START, + VALUE_SIMPLE, + VALUE_DOUBLE_QUOTES, + VALUE_TICKS + } state; + const char *p, *key, *value; size_t key_len = 0, value_len = 0; @@ -100,6 +112,8 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { case KEY: if (*p == '=') state = VALUE_START; + else if (isspace(*p)) + goto fail; else key_len++; break; diff --git a/src/pulsecore/modargs.h b/src/pulsecore/modargs.h index 504b9cd7..23766cfc 100644 --- a/src/pulsecore/modargs.h +++ b/src/pulsecore/modargs.h @@ -1,8 +1,6 @@ #ifndef foomodargshfoo #define foomodargshfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/modinfo.c b/src/pulsecore/modinfo.c index d1a78fbb..ac4ca88a 100644 --- a/src/pulsecore/modinfo.c +++ b/src/pulsecore/modinfo.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/modinfo.h b/src/pulsecore/modinfo.h index da6d5428..605637c4 100644 --- a/src/pulsecore/modinfo.h +++ b/src/pulsecore/modinfo.h @@ -1,8 +1,6 @@ #ifndef foomodinfohfoo #define foomodinfohfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c index 8e5bd2d1..f1eeb762 100644 --- a/src/pulsecore/module.c +++ b/src/pulsecore/module.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -120,7 +118,7 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { if (!c->modules) c->modules = pa_idxset_new(NULL, NULL); - if (!c->module_auto_unload_event) { + if (m->auto_unload && !c->module_auto_unload_event) { struct timeval ntv; pa_gettimeofday(&ntv); pa_timeval_add(&ntv, UNLOAD_POLL_TIME*1000000); diff --git a/src/pulsecore/module.h b/src/pulsecore/module.h index 68c7238d..ec582f25 100644 --- a/src/pulsecore/module.h +++ b/src/pulsecore/module.h @@ -1,8 +1,6 @@ #ifndef foomodulehfoo #define foomodulehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/msgobject.c b/src/pulsecore/msgobject.c index f54e69f2..81417ea4 100644 --- a/src/pulsecore/msgobject.c +++ b/src/pulsecore/msgobject.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/msgobject.h b/src/pulsecore/msgobject.h index 8221cc33..1a43fa35 100644 --- a/src/pulsecore/msgobject.h +++ b/src/pulsecore/msgobject.h @@ -1,8 +1,6 @@ #ifndef foopulsemsgobjecthfoo #define foopulsemsgobjecthfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/mutex-posix.c b/src/pulsecore/mutex-posix.c index 6ac98484..35465b7b 100644 --- a/src/pulsecore/mutex-posix.c +++ b/src/pulsecore/mutex-posix.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/mutex-win32.c b/src/pulsecore/mutex-win32.c index 77d63d15..5e884e7f 100644 --- a/src/pulsecore/mutex-win32.c +++ b/src/pulsecore/mutex-win32.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/mutex.h b/src/pulsecore/mutex.h index 9ca8fae5..36e1d635 100644 --- a/src/pulsecore/mutex.h +++ b/src/pulsecore/mutex.h @@ -1,8 +1,6 @@ #ifndef foopulsemutexhfoo #define foopulsemutexhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index 1b0977d7..cc18adab 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h index 0f5b4d4d..af0153ec 100644 --- a/src/pulsecore/namereg.h +++ b/src/pulsecore/namereg.h @@ -1,8 +1,6 @@ #ifndef foonamereghfoo #define foonamereghfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h index 56f9037e..809d6c75 100644 --- a/src/pulsecore/native-common.h +++ b/src/pulsecore/native-common.h @@ -1,8 +1,6 @@ #ifndef foonativecommonhfoo #define foonativecommonhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/object.c b/src/pulsecore/object.c index 6c36242b..9a2f28f3 100644 --- a/src/pulsecore/object.c +++ b/src/pulsecore/object.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/object.h b/src/pulsecore/object.h index 562fd113..7dcfa2eb 100644 --- a/src/pulsecore/object.h +++ b/src/pulsecore/object.h @@ -1,8 +1,6 @@ #ifndef foopulseobjecthfoo #define foopulseobjecthfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/once.c b/src/pulsecore/once.c index a358cf65..989741dc 100644 --- a/src/pulsecore/once.c +++ b/src/pulsecore/once.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/once.h b/src/pulsecore/once.h index c9fe6d0a..576d40fa 100644 --- a/src/pulsecore/once.h +++ b/src/pulsecore/once.h @@ -1,8 +1,6 @@ #ifndef foopulseoncehfoo #define foopulseoncehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/packet.c b/src/pulsecore/packet.c index 2706efea..cee468bd 100644 --- a/src/pulsecore/packet.c +++ b/src/pulsecore/packet.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/packet.h b/src/pulsecore/packet.h index bcac4a7f..5989b1fa 100644 --- a/src/pulsecore/packet.h +++ b/src/pulsecore/packet.h @@ -1,8 +1,6 @@ #ifndef foopackethfoo #define foopackethfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/parseaddr.c b/src/pulsecore/parseaddr.c index 149c9e00..f2b6b2cf 100644 --- a/src/pulsecore/parseaddr.c +++ b/src/pulsecore/parseaddr.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/parseaddr.h b/src/pulsecore/parseaddr.h index fd7cad3b..5fbcb9a7 100644 --- a/src/pulsecore/parseaddr.h +++ b/src/pulsecore/parseaddr.h @@ -1,8 +1,6 @@ #ifndef fooparseaddrhfoo #define fooparseaddrhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index bdd7cde1..e6a6ae4d 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/pdispatch.h b/src/pulsecore/pdispatch.h index de0aa3ec..5c31d80e 100644 --- a/src/pulsecore/pdispatch.h +++ b/src/pulsecore/pdispatch.h @@ -1,8 +1,6 @@ #ifndef foopdispatchhfoo #define foopdispatchhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c index 2ff132bb..addb17cc 100644 --- a/src/pulsecore/pid.c +++ b/src/pulsecore/pid.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -140,8 +138,51 @@ fail: return -1; } +static int proc_name_ours(pid_t pid, const char *procname) { +#ifdef __linux__ + char bn[PATH_MAX]; + FILE *f; + + pa_snprintf(bn, sizeof(bn), "/proc/%lu/stat", (unsigned long) pid); + + if (!(f = fopen(bn, "r"))) { + pa_log_info("Failed to open %s: %s", bn, pa_cstrerror(errno)); + return -1; + } else { + char *expected; + pa_bool_t good; + char stored[64]; + + if (!(fgets(stored, sizeof(stored), f))) { + pa_log_info("Failed to read from %s: %s", bn, feof(f) ? "EOF" : pa_cstrerror(errno)); + fclose(f); + return -1; + } + + fclose(f); + + expected = pa_sprintf_malloc("%lu (%s)", (unsigned long) pid, procname); + good = pa_startswith(stored, expected); + pa_xfree(expected); + +#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 + + return !!good; + } +#endif + + return 1; +} + /* Create a new PID file for the current process. */ -int pa_pid_file_create(void) { +int pa_pid_file_create(const char *procname) { int fd = -1; int ret = -1; char t[20]; @@ -153,7 +194,8 @@ int pa_pid_file_create(void) { HANDLE process; #endif - fn = pa_runtime_path("pid"); + if (!(fn = pa_runtime_path("pid"))) + goto fail; if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0) goto fail; @@ -161,14 +203,24 @@ int pa_pid_file_create(void) { if ((pid = read_pid(fn, fd)) == (pid_t) -1) pa_log_warn("Corrupt PID file, overwriting."); else if (pid > 0) { + #ifdef OS_IS_WIN32 if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) { CloseHandle(process); #else if (kill(pid, 0) >= 0 || errno != ESRCH) { #endif - pa_log("Daemon already running."); - goto fail; + int ours = 1; + + if (procname) + if ((ours = proc_name_ours(pid, procname)) < 0) + goto fail; + + if (ours) { + pa_log("Daemon already running."); + ret = 1; + goto fail; + } } pa_log_warn("Stale PID file, overwriting."); @@ -212,7 +264,8 @@ int pa_pid_file_remove(void) { int ret = -1; pid_t pid; - fn = pa_runtime_path("pid"); + if (!(fn = pa_runtime_path("pid"))) + goto fail; if ((fd = open_pid_file(fn, O_RDWR)) < 0) { pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno)); @@ -234,7 +287,7 @@ int pa_pid_file_remove(void) { #ifdef OS_IS_WIN32 pa_lock_fd(fd, 0); - close(fd); + pa_close(fd); fd = -1; #endif @@ -265,8 +318,8 @@ fail: * exists and the PID therein too. Returns 0 on succcess, -1 * otherwise. If pid is non-NULL and a running daemon was found, * return its PID therein */ -int pa_pid_file_check_running(pid_t *pid, const char *binary_name) { - return pa_pid_file_kill(0, pid, binary_name); +int pa_pid_file_check_running(pid_t *pid, const char *procname) { + return pa_pid_file_kill(0, pid, procname); } #ifndef OS_IS_WIN32 @@ -274,7 +327,7 @@ int pa_pid_file_check_running(pid_t *pid, const char *binary_name) { /* Kill a current running daemon. Return non-zero on success, -1 * otherwise. If successful *pid contains the PID of the daemon * process. */ -int pa_pid_file_kill(int sig, pid_t *pid, const char *binary_name) { +int pa_pid_file_kill(int sig, pid_t *pid, const char *procname) { int fd = -1; char *fn; int ret = -1; @@ -282,10 +335,12 @@ int pa_pid_file_kill(int sig, pid_t *pid, const char *binary_name) { #ifdef __linux__ char *e = NULL; #endif + if (!pid) pid = &_pid; - fn = pa_runtime_path("pid"); + if (!(fn = pa_runtime_path("pid"))) + goto fail; if ((fd = open_pid_file(fn, O_RDONLY)) < 0) goto fail; @@ -293,22 +348,15 @@ int pa_pid_file_kill(int sig, pid_t *pid, const char *binary_name) { if ((*pid = read_pid(fn, fd)) == (pid_t) -1) goto fail; -#ifdef __linux__ - if (binary_name) { - pa_snprintf(fn, sizeof(fn), "/proc/%lu/exe", (unsigned long) pid); + if (procname) { + int ours; - if ((e = pa_readlink(fn))) { - char *f = pa_path_get_filename(e); - if (strcmp(f, binary_name) -#if !defined(__OPTIMIZE__) - /* libtool likes to rename our binary names ... */ - && !(pa_startswith(f, "lt-") && strcmp(f+3, binary_name) == 0) -#endif - ) - goto fail; - } + if ((ours = proc_name_ours(*pid, procname)) < 0) + goto fail; + + if (!ours) + goto fail; } -#endif ret = kill(*pid, sig); diff --git a/src/pulsecore/pid.h b/src/pulsecore/pid.h index 1d6de7b5..3c8a9de3 100644 --- a/src/pulsecore/pid.h +++ b/src/pulsecore/pid.h @@ -1,8 +1,6 @@ #ifndef foopidhfoo #define foopidhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -24,9 +22,9 @@ USA. ***/ -int pa_pid_file_create(void); +int pa_pid_file_create(const char *procname); int pa_pid_file_remove(void); -int pa_pid_file_check_running(pid_t *pid, const char *binary_name); -int pa_pid_file_kill(int sig, pid_t *pid, const char *binary_name); +int pa_pid_file_check_running(pid_t *pid, const char *procname); +int pa_pid_file_kill(int sig, pid_t *pid, const char *procname); #endif diff --git a/src/pulsecore/pipe.c b/src/pulsecore/pipe.c index e614c9c6..93d78a22 100644 --- a/src/pulsecore/pipe.c +++ b/src/pulsecore/pipe.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/pipe.h b/src/pulsecore/pipe.h index e013a2e7..9a7e62c8 100644 --- a/src/pulsecore/pipe.h +++ b/src/pulsecore/pipe.h @@ -1,8 +1,6 @@ #ifndef foopipehfoo #define foopipehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c index 2688f923..8b3e79b9 100644 --- a/src/pulsecore/play-memblockq.c +++ b/src/pulsecore/play-memblockq.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -138,6 +136,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk return -1; } + chunk->length = PA_MIN(chunk->length, nbytes); pa_memblockq_drop(u->memblockq, chunk->length); return 0; diff --git a/src/pulsecore/play-memblockq.h b/src/pulsecore/play-memblockq.h index 9ecf7700..1a42867b 100644 --- a/src/pulsecore/play-memblockq.h +++ b/src/pulsecore/play-memblockq.h @@ -1,8 +1,6 @@ #ifndef fooplaymemblockqhfoo #define fooplaymemblockqhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/play-memchunk.c b/src/pulsecore/play-memchunk.c index 67a92138..0dd48251 100644 --- a/src/pulsecore/play-memchunk.c +++ b/src/pulsecore/play-memchunk.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/play-memchunk.h b/src/pulsecore/play-memchunk.h index f7c9d178..c312ae82 100644 --- a/src/pulsecore/play-memchunk.h +++ b/src/pulsecore/play-memchunk.h @@ -1,8 +1,6 @@ #ifndef fooplaychunkhfoo #define fooplaychunkhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c index 288f7dfb..88ac21e4 100644 --- a/src/pulsecore/poll.c +++ b/src/pulsecore/poll.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/poll.h b/src/pulsecore/poll.h index 6be6069b..86c37a08 100644 --- a/src/pulsecore/poll.h +++ b/src/pulsecore/poll.h @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c new file mode 100644 index 00000000..6005775e --- /dev/null +++ b/src/pulsecore/proplist-util.c @@ -0,0 +1,118 @@ +/*** + 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. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <locale.h> + +#include <pulse/proplist.h> +#include <pulse/utf8.h> +#include <pulse/xmalloc.h> +#include <pulse/util.h> + +#include <pulsecore/core-util.h> + +#include "proplist-util.h" + +void pa_init_proplist(pa_proplist *p) { + int a, b; +#ifndef HAVE_DECL_ENVIRON + extern char **environ; +#endif + char **e; + + pa_assert(p); + + for (e = environ; *e; e++) { + + if (pa_startswith(*e, "PULSE_PROP_")) { + size_t kl = strcspn(*e+11, "="); + char *k; + + if ((*e)[11+kl] != '=') + continue; + + if (!pa_utf8_valid(*e+11+kl+1)) + continue; + + k = pa_xstrndup(*e+11, kl); + + if (pa_proplist_contains(p, k)) { + pa_xfree(k); + continue; + } + + pa_proplist_sets(p, k, *e+11+kl+1); + pa_xfree(k); + } + } + + if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_ID)) { + char t[32]; + pa_snprintf(t, sizeof(t), "%lu", (unsigned long) getpid()); + pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_ID, t); + } + + if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_USER)) { + char t[64]; + if (pa_get_user_name(t, sizeof(t))) { + char *c = pa_utf8_filter(t); + pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_USER, c); + pa_xfree(c); + } + } + + if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_HOST)) { + char t[64]; + if (pa_get_host_name(t, sizeof(t))) { + char *c = pa_utf8_filter(t); + pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_HOST, c); + pa_xfree(c); + } + } + + a = pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_BINARY); + b = pa_proplist_contains(p, PA_PROP_APPLICATION_NAME); + + if (!a || !b) { + char t[PATH_MAX]; + if (pa_get_binary_name(t, sizeof(t))) { + char *c = pa_utf8_filter(t); + + if (!a) + pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_BINARY, c); + if (!b) + pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, c); + + pa_xfree(c); + } + } + + if (!pa_proplist_contains(p, PA_PROP_APPLICATION_LANGUAGE)) { + const char *l; + + if ((l = setlocale(LC_MESSAGES, NULL))) + pa_proplist_sets(p, PA_PROP_APPLICATION_LANGUAGE, l); + } +} diff --git a/src/pulsecore/proplist-util.h b/src/pulsecore/proplist-util.h new file mode 100644 index 00000000..c6bdc103 --- /dev/null +++ b/src/pulsecore/proplist-util.h @@ -0,0 +1,29 @@ +#ifndef fooproplistutilutilhfoo +#define fooproplistutilutilhfoo + +/*** + 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 <pulse/proplist.h> + +void pa_init_proplist(pa_proplist *p); + +#endif diff --git a/src/pulsecore/props.c b/src/pulsecore/props.c index cbf748df..23d432ec 100644 --- a/src/pulsecore/props.c +++ b/src/pulsecore/props.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/props.h b/src/pulsecore/props.h index 880325f6..95db229b 100644 --- a/src/pulsecore/props.h +++ b/src/pulsecore/props.h @@ -1,8 +1,6 @@ #ifndef foopropshfoo #define foopropshfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/protocol-cli.c b/src/pulsecore/protocol-cli.c index 2f797a14..30cb475d 100644 --- a/src/pulsecore/protocol-cli.c +++ b/src/pulsecore/protocol-cli.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/protocol-cli.h b/src/pulsecore/protocol-cli.h index 3870def3..8922ac62 100644 --- a/src/pulsecore/protocol-cli.h +++ b/src/pulsecore/protocol-cli.h @@ -1,8 +1,6 @@ #ifndef fooprotocolclihfoo #define fooprotocolclihfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 492dc9fa..db1b4305 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -1042,7 +1040,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); @@ -1275,6 +1273,8 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk } else { size_t m; + chunk->length = PA_MIN(length, chunk->length); + c->playback.underrun = FALSE; pa_memblockq_drop(c->input_memblockq, chunk->length); diff --git a/src/pulsecore/protocol-esound.h b/src/pulsecore/protocol-esound.h index 868ef5d2..0c9447d3 100644 --- a/src/pulsecore/protocol-esound.h +++ b/src/pulsecore/protocol-esound.h @@ -1,8 +1,6 @@ #ifndef fooprotocolesoundhfoo #define fooprotocolesoundhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c index bc2e9af6..03990435 100644 --- a/src/pulsecore/protocol-http.c +++ b/src/pulsecore/protocol-http.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/protocol-http.h b/src/pulsecore/protocol-http.h index cf952476..e3372335 100644 --- a/src/pulsecore/protocol-http.h +++ b/src/pulsecore/protocol-http.h @@ -1,8 +1,6 @@ #ifndef fooprotocolhttphfoo #define fooprotocolhttphfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 2adcdfc7..923a5665 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -132,7 +130,8 @@ typedef struct upload_stream { struct connection { pa_msgobject parent; - pa_bool_t authorized; + pa_bool_t authorized:1; + pa_bool_t is_local:1; uint32_t version; pa_protocol_native *protocol; pa_client *client; @@ -485,7 +484,7 @@ static void fix_record_buffer_attr_pre(record_stream *s, pa_bool_t adjust_latenc pa_usec_t fragsize_usec; /* So, the user asked us to adjust the latency according to - * the what the source can provide. Half the latency will be + * 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. */ @@ -499,7 +498,8 @@ static void fix_record_buffer_attr_pre(record_stream *s, pa_bool_t adjust_latenc fragsize_usec = s->source_latency; *fragsize = pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec); - } + } else + s->source_latency = 0; } static void fix_record_buffer_attr_post(record_stream *s, uint32_t *maxlength, uint32_t *fragsize) { @@ -533,7 +533,8 @@ static record_stream* record_stream_new( uint32_t *fragsize, pa_source_output_flags_t flags, pa_proplist *p, - pa_bool_t adjust_latency) { + pa_bool_t adjust_latency, + pa_sink_input *direct_on_input) { record_stream *s; pa_source_output *source_output; @@ -553,6 +554,7 @@ static record_stream* record_stream_new( data.module = c->protocol->module; data.client = c->client; data.source = source; + data.direct_on_input = direct_on_input; pa_source_output_new_data_set_sample_spec(&data, ss); pa_source_output_new_data_set_channel_map(&data, map); if (peak_detect) @@ -597,6 +599,11 @@ static record_stream* record_stream_new( pa_idxset_put(c->record_streams, s, &s->index); + pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms", + ((double) pa_bytes_to_usec(s->fragment_size, &source_output->sample_spec) + (double) s->source_latency) / PA_USEC_PER_MSEC, + (double) pa_bytes_to_usec(s->fragment_size, &source_output->sample_spec) / PA_USEC_PER_MSEC, + (double) s->source_latency / PA_USEC_PER_MSEC); + pa_source_output_put(s->source_output); return s; } @@ -803,7 +810,7 @@ static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_la if (*tlength <= *minreq) *tlength = *minreq*2 + frame_size; - if (*prebuf <= 0) + if (*prebuf <= 0 || *prebuf > *tlength) *prebuf = *tlength; } @@ -1281,7 +1288,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk if (pa_memblockq_peek(s->memblockq, chunk) < 0) { -/* pa_log("UNDERRUN: %lu", pa_memblockq_get_length(s->memblockq)); */ +/* pa_log("UNDERRUN: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */ if (s->drain_request && pa_sink_input_safe_to_remove(i)) { s->drain_request = FALSE; @@ -1298,6 +1305,8 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk /* pa_log("NOTUNDERRUN %lu", (unsigned long) chunk->length); */ + chunk->length = PA_MIN(nbytes, chunk->length); + if (i->thread_info.underrun_for > 0) pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL); @@ -1750,7 +1759,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ record_stream *s; uint32_t maxlength, fragment_size; uint32_t source_index; - const char *name, *source_name; + const char *name = NULL, *source_name; pa_sample_spec ss; pa_channel_map map; pa_tagstruct *reply; @@ -1768,6 +1777,8 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ peak_detect = FALSE; pa_source_output_flags_t flags = 0; pa_proplist *p; + uint32_t direct_on_input_idx = PA_INVALID_INDEX; + pa_sink_input *direct_on_input = NULL; connection_assert_ref(c); pa_assert(t); @@ -1816,7 +1827,8 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 || pa_tagstruct_get_boolean(t, &adjust_latency) < 0 || - pa_tagstruct_get_proplist(t, p) < 0) { + pa_tagstruct_get_proplist(t, p) < 0 || + pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) { protocol_error(c); pa_proplist_free(p); return; @@ -1846,6 +1858,15 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } } + if (direct_on_input_idx != PA_INVALID_INDEX) { + + if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) { + pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); + pa_proplist_free(p); + return; + } + } + flags = (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) | (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) | @@ -1856,7 +1877,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) | (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0); - s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency); + s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input); pa_proplist_free(p); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); @@ -1914,7 +1935,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t connection *c = CONNECTION(userdata); const void*cookie; pa_tagstruct *reply; - char tmp[16]; + pa_bool_t shm_on_remote, do_shm; connection_assert_ref(c); pa_assert(t); @@ -1932,8 +1953,17 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t return; } - pa_snprintf(tmp, sizeof(tmp), "%u", c->version); - pa_proplist_sets(c->client->proplist, "native-protocol.version", tmp); + /* Starting with protocol version 13 the MSB of the version tag + reflects if shm is available for this connection or + not. */ + if (c->version >= 13) { + shm_on_remote = !!(c->version & 0x80000000U); + c->version &= 0x7FFFFFFFU; + } + + pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION); + + pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version); if (!c->authorized) { pa_bool_t success = FALSE; @@ -1964,16 +1994,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t pa_log_info("Got credentials: uid=%lu gid=%lu success=%i", (unsigned long) creds->uid, (unsigned long) creds->gid, - success); - - if (c->version >= 10 && - pa_mempool_is_shared(c->protocol->core->mempool) && - creds->uid == getuid()) { - - pa_pstream_enable_shm(c->pstream, TRUE); - pa_log_info("Enabled SHM for new connection"); - } - + (int) success); } #endif @@ -1993,8 +2014,32 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t } } + /* Enable shared memory support if possible */ + do_shm = + pa_mempool_is_shared(c->protocol->core->mempool) && + c->is_local; + + pa_log_debug("SHM possible: %s", pa_yes_no(do_shm)); + + if (do_shm) + if (c->version < 10 || (c->version >= 13 && !shm_on_remote)) + do_shm = FALSE; + + if (do_shm) { + /* Only enable SHM if both sides are owned by the same + * user. This is a security measure because otherwise data + * private to the user might leak. */ + + const pa_creds *creds; + if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid) + do_shm = FALSE; + } + + pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm)); + pa_pstream_enable_shm(c->pstream, do_shm); + reply = reply_new(tag); - pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION); + pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0)); #ifdef HAVE_CREDS { @@ -2229,7 +2274,7 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ connection_assert_ref(c); pa_assert(t); - if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) || + if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_get_channel_map(t, &map) < 0 || pa_tagstruct_getu32(t, &length) < 0) { @@ -2244,9 +2289,6 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE); - if (c->version < 13) - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - p = pa_proplist_new(); if (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) { @@ -2257,6 +2299,11 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ if (c->version < 13) pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name); + else if (!name) + 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); s = upload_stream_new(c, &ss, &map, name, length, p); pa_proplist_free(p); @@ -2488,6 +2535,7 @@ static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { static void sink_input_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink_input *s) { pa_sample_spec fixed_ss; + pa_usec_t sink_latency; pa_assert(t); pa_sink_input_assert_ref(s); @@ -2502,8 +2550,8 @@ static void sink_input_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink_in 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_usec(t, pa_sink_input_get_latency(s)); - pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); + 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))); pa_tagstruct_puts(t, s->driver); if (c->version >= 11) @@ -2514,6 +2562,7 @@ static void sink_input_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink_in static void source_output_fill_tagstruct(connection *c, pa_tagstruct *t, pa_source_output *s) { pa_sample_spec fixed_ss; + pa_usec_t source_latency; pa_assert(t); pa_source_output_assert_ref(s); @@ -2527,8 +2576,8 @@ static void source_output_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sour pa_tagstruct_putu32(t, s->source->index); pa_tagstruct_put_sample_spec(t, &fixed_ss); pa_tagstruct_put_channel_map(t, &s->channel_map); - pa_tagstruct_put_usec(t, pa_source_output_get_latency(s)); - pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); + pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency)); + pa_tagstruct_put_usec(t, source_latency); pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s))); pa_tagstruct_puts(t, s->driver); @@ -2542,12 +2591,15 @@ static void scache_fill_tagstruct(connection *c, pa_tagstruct *t, pa_scache_entr pa_assert(t); pa_assert(e); - fixup_sample_spec(c, &fixed_ss, &e->sample_spec); + if (e->memchunk.memblock) + fixup_sample_spec(c, &fixed_ss, &e->sample_spec); + else + memset(&fixed_ss, 0, sizeof(fixed_ss)); pa_tagstruct_putu32(t, e->index); pa_tagstruct_puts(t, e->name); pa_tagstruct_put_cvolume(t, &e->volume); - pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); + 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); @@ -3885,7 +3937,6 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo connection *c; char cname[256], pname[128]; - pa_assert(s); pa_assert(io); pa_assert(p); @@ -3914,6 +3965,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo } else c->auth_timeout_event = NULL; + c->is_local = pa_iochannel_socket_is_local(io); c->version = 8; c->protocol = p; pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); @@ -3946,7 +3998,6 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo #ifdef HAVE_CREDS if (pa_iochannel_creds_supported(io)) pa_iochannel_creds_enable(io); - #endif } @@ -4005,7 +4056,7 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo pa_log("auth-group-enabled= expects a boolean argument."); return NULL; } - p->auth_group = a ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", c->is_system_instance ? PA_ACCESS_GROUP : NULL)) : NULL; + p->auth_group = a ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL; if (p->auth_group) pa_log_info("Allowing access to group '%s'.", p->auth_group); diff --git a/src/pulsecore/protocol-native.h b/src/pulsecore/protocol-native.h index bf05f937..a52fa8cf 100644 --- a/src/pulsecore/protocol-native.h +++ b/src/pulsecore/protocol-native.h @@ -1,8 +1,6 @@ #ifndef fooprotocolnativehfoo #define fooprotocolnativehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index cbe48440..020a281d 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -374,6 +372,8 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk } else { size_t m; + chunk->length = PA_MIN(length, chunk->length); + c->playback.underrun = FALSE; pa_memblockq_drop(c->input_memblockq, chunk->length); diff --git a/src/pulsecore/protocol-simple.h b/src/pulsecore/protocol-simple.h index 3b02c88e..e1b3143b 100644 --- a/src/pulsecore/protocol-simple.h +++ b/src/pulsecore/protocol-simple.h @@ -1,8 +1,6 @@ #ifndef fooprotocolsimplehfoo #define fooprotocolsimplehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/pstream-util.c b/src/pulsecore/pstream-util.c index a6932158..f84f486a 100644 --- a/src/pulsecore/pstream-util.c +++ b/src/pulsecore/pstream-util.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/pstream-util.h b/src/pulsecore/pstream-util.h index 67759f2a..ae0d79c3 100644 --- a/src/pulsecore/pstream-util.h +++ b/src/pulsecore/pstream-util.h @@ -1,8 +1,6 @@ #ifndef foopstreamutilhfoo #define foopstreamutilhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 5004d67f..e26ca473 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h index 00b37b71..a528b25c 100644 --- a/src/pulsecore/pstream.h +++ b/src/pulsecore/pstream.h @@ -1,8 +1,6 @@ #ifndef foopstreamhfoo #define foopstreamhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/queue.c b/src/pulsecore/queue.c index 9b6a37f0..08fd1426 100644 --- a/src/pulsecore/queue.c +++ b/src/pulsecore/queue.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/queue.h b/src/pulsecore/queue.h index cd767364..b09216cf 100644 --- a/src/pulsecore/queue.h +++ b/src/pulsecore/queue.h @@ -1,8 +1,6 @@ #ifndef fooqueuehfoo #define fooqueuehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/random.c b/src/pulsecore/random.c index 87afebfa..5deac37b 100644 --- a/src/pulsecore/random.c +++ b/src/pulsecore/random.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -64,7 +62,11 @@ static int random_proper(void *ret_data, size_t length) { while (*device) { ret = 0; - if ((fd = open(*device, O_RDONLY)) >= 0) { + if ((fd = open(*device, O_RDONLY +#ifdef O_NOCTTY + | O_NOCTTY +#endif + )) >= 0) { if ((r = pa_loop_read(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) ret = -1; diff --git a/src/pulsecore/random.h b/src/pulsecore/random.h index 01b7d746..36d7f9df 100644 --- a/src/pulsecore/random.h +++ b/src/pulsecore/random.h @@ -1,8 +1,6 @@ #ifndef foorandomhfoo #define foorandomhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/refcnt.h b/src/pulsecore/refcnt.h index f0885fb4..291f4504 100644 --- a/src/pulsecore/refcnt.h +++ b/src/pulsecore/refcnt.h @@ -1,8 +1,6 @@ #ifndef foopulserefcnthfoo #define foopulserefcnthfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index d645639c..00dc794c 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -1457,10 +1455,10 @@ static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned i r->peaks.max_i[c] = n; } - for (c = 0; c < r->o_ss.channels; c++, d++) + for (c = 0; c < r->o_ss.channels; c++, d++) { *d = r->peaks.max_i[c]; - - memset(r->peaks.max_i, 0, sizeof(r->peaks.max_i)); + r->peaks.max_i[c] = 0; + } } else { unsigned i, c; float *s = (float*) ((uint8_t*) src + fz * j); @@ -1476,11 +1474,13 @@ static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned i r->peaks.max_f[c] = n; } - for (c = 0; c < r->o_ss.channels; c++, d++) + for (c = 0; c < r->o_ss.channels; c++, d++) { *d = r->peaks.max_f[c]; - - memset(r->peaks.max_f, 0, sizeof(r->peaks.max_f)); + r->peaks.max_f[c] = 0; + } } + + start = j+1; } pa_memblock_release(input->memblock); diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h index 8534f5b5..5e302a9b 100644 --- a/src/pulsecore/resampler.h +++ b/src/pulsecore/resampler.h @@ -1,8 +1,6 @@ #ifndef fooresamplerhfoo #define fooresamplerhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/rtclock.c b/src/pulsecore/rtclock.c index e74e5243..f33de830 100644 --- a/src/pulsecore/rtclock.c +++ b/src/pulsecore/rtclock.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/rtclock.h b/src/pulsecore/rtclock.h index f68ad761..705de48f 100644 --- a/src/pulsecore/rtclock.h +++ b/src/pulsecore/rtclock.h @@ -1,8 +1,6 @@ #ifndef foopulsertclockhfoo #define foopulsertclockhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/rtpoll.c b/src/pulsecore/rtpoll.c index 64fa42ad..a67a5516 100644 --- a/src/pulsecore/rtpoll.c +++ b/src/pulsecore/rtpoll.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -514,6 +512,9 @@ void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, pa_usec_t usec) { void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) { pa_assert(p); + /* Scheduling a timeout for more than an hour is very very suspicious */ + pa_assert(usec <= PA_USEC_PER_SEC*60ULL*60ULL); + pa_rtclock_get(&p->next_elapse); pa_timeval_add(&p->next_elapse, usec); p->timer_enabled = TRUE; diff --git a/src/pulsecore/rtpoll.h b/src/pulsecore/rtpoll.h index 16dadbc3..08776ef0 100644 --- a/src/pulsecore/rtpoll.h +++ b/src/pulsecore/rtpoll.h @@ -1,8 +1,6 @@ #ifndef foopulsertpollhfoo #define foopulsertpollhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/rtsig.c b/src/pulsecore/rtsig.c index bfc49c88..4df217c3 100644 --- a/src/pulsecore/rtsig.c +++ b/src/pulsecore/rtsig.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/rtsig.h b/src/pulsecore/rtsig.h index 7830d272..e414122d 100644 --- a/src/pulsecore/rtsig.h +++ b/src/pulsecore/rtsig.h @@ -1,8 +1,6 @@ #ifndef foopulsertsighfoo #define foopulsertsighfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index a8028296..b42b79d1 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 59b4c632..cef70750 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -1,8 +1,6 @@ #ifndef foosampleutilhfoo #define foosampleutilhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/sconv-s16be.c b/src/pulsecore/sconv-s16be.c index 638beb2e..e7e1449a 100644 --- a/src/pulsecore/sconv-s16be.c +++ b/src/pulsecore/sconv-s16be.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/sconv-s16be.h b/src/pulsecore/sconv-s16be.h index 454c9508..60580815 100644 --- a/src/pulsecore/sconv-s16be.h +++ b/src/pulsecore/sconv-s16be.h @@ -1,8 +1,6 @@ #ifndef foosconv_s16befoo #define foosconv_s16befoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c index 90e9b6d2..41670f27 100644 --- a/src/pulsecore/sconv-s16le.c +++ b/src/pulsecore/sconv-s16le.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/sconv-s16le.h b/src/pulsecore/sconv-s16le.h index 4165f8a2..8d4c87c3 100644 --- a/src/pulsecore/sconv-s16le.h +++ b/src/pulsecore/sconv-s16le.h @@ -1,8 +1,6 @@ #ifndef foosconv_s16lefoo #define foosconv_s16lefoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index ebd74586..581e4681 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/sconv.h b/src/pulsecore/sconv.h index 901f50a3..59710369 100644 --- a/src/pulsecore/sconv.h +++ b/src/pulsecore/sconv.h @@ -1,8 +1,6 @@ #ifndef foosconvhfoo #define foosconvhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/semaphore-posix.c b/src/pulsecore/semaphore-posix.c index 750c2afc..7c9f859d 100644 --- a/src/pulsecore/semaphore-posix.c +++ b/src/pulsecore/semaphore-posix.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/semaphore-win32.c b/src/pulsecore/semaphore-win32.c index f6576348..41e0b8d4 100644 --- a/src/pulsecore/semaphore-win32.c +++ b/src/pulsecore/semaphore-win32.c @@ -1,5 +1,3 @@ -/* $Id: mutex-win32.c 1426 2007-02-13 15:35:19Z ossman $ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/semaphore.h b/src/pulsecore/semaphore.h index c394e0f2..850ae817 100644 --- a/src/pulsecore/semaphore.h +++ b/src/pulsecore/semaphore.h @@ -1,8 +1,6 @@ #ifndef foopulsesemaphorehfoo #define foopulsesemaphorehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index a6843819..298bf716 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/shm.h b/src/pulsecore/shm.h index 60bc355f..c2adbd07 100644 --- a/src/pulsecore/shm.h +++ b/src/pulsecore/shm.h @@ -1,8 +1,6 @@ #ifndef foopulseshmhfoo #define foopulseshmhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/shmasyncq.c b/src/pulsecore/shmasyncq.c index 7af2985c..eac56adb 100644 --- a/src/pulsecore/shmasyncq.c +++ b/src/pulsecore/shmasyncq.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/shmasyncq.h b/src/pulsecore/shmasyncq.h index ca35ffd2..9845c391 100644 --- a/src/pulsecore/shmasyncq.h +++ b/src/pulsecore/shmasyncq.h @@ -1,8 +1,6 @@ #ifndef foopulseshmasyncqhfoo #define foopulseshmasyncqhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index d51ff810..43e7bb21 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -44,7 +42,6 @@ #define MEMBLOCKQ_MAXLENGTH (32*1024*1024) #define CONVERT_BUFFER_LENGTH (PA_PAGE_SIZE) -#define MOVE_BUFFER_LENGTH (PA_PAGE_SIZE*256) static PA_DEFINE_CHECK_TYPE(pa_sink_input, pa_msgobject); @@ -94,12 +91,16 @@ void pa_sink_input_new_data_done(pa_sink_input_new_data *data) { pa_proplist_free(data->proplist); } +/* Called from main context */ static void reset_callbacks(pa_sink_input *i) { pa_assert(i); i->pop = NULL; i->process_rewind = NULL; i->update_max_rewind = NULL; + i->update_max_request = NULL; + i->update_sink_requested_latency = NULL; + i->update_sink_latency_range = NULL; i->attach = NULL; i->detach = NULL; i->suspend = NULL; @@ -109,6 +110,7 @@ static void reset_callbacks(pa_sink_input *i) { i->state_change = NULL; } +/* Called from main context */ pa_sink_input* pa_sink_input_new( pa_core *core, pa_sink_input_new_data *data, @@ -127,7 +129,7 @@ pa_sink_input* pa_sink_input_new( pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver)); if (!data->sink) - data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK, 1); + data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK, TRUE); pa_return_null_if_fail(data->sink); pa_return_null_if_fail(pa_sink_get_state(data->sink) != PA_SINK_UNLINKED); @@ -237,6 +239,8 @@ pa_sink_input* pa_sink_input_new( } else i->sync_next = i->sync_prev = NULL; + i->direct_outputs = pa_idxset_new(NULL, NULL); + reset_callbacks(i); i->userdata = NULL; @@ -252,6 +256,7 @@ pa_sink_input* pa_sink_input_new( i->thread_info.rewrite_flush = FALSE; i->thread_info.underrun_for = (uint64_t) -1; i->thread_info.playing_for = 0; + i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); i->thread_info.render_memblockq = pa_memblockq_new( 0, @@ -278,6 +283,7 @@ pa_sink_input* pa_sink_input_new( return i; } +/* Called from main context */ static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) { pa_assert(i); @@ -289,6 +295,7 @@ static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) { pa_sink_update_status(i->sink); } +/* Called from main context */ static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) { pa_sink_input *ssync; pa_assert(i); @@ -299,8 +306,7 @@ static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) { if (i->state == state) return 0; - if (pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0) - return -1; + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0); update_n_corked(i, state); i->state = state; @@ -314,14 +320,23 @@ static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) { ssync->state = state; } - if (state != PA_SINK_INPUT_UNLINKED) + if (state != PA_SINK_INPUT_UNLINKED) { pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], i); + for (ssync = i->sync_prev; ssync; ssync = ssync->sync_prev) + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], ssync); + + for (ssync = i->sync_next; ssync; ssync = ssync->sync_next) + pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], ssync); + } + return 0; } +/* Called from main context */ void pa_sink_input_unlink(pa_sink_input *i) { pa_bool_t linked; + pa_source_output *o, *p = NULL; pa_assert(i); /* See pa_sink_unlink() for a couple of comments how this function @@ -345,12 +360,18 @@ void pa_sink_input_unlink(pa_sink_input *i) { if (pa_idxset_remove_by_data(i->sink->inputs, i, NULL)) pa_sink_input_unref(i); + while ((o = pa_idxset_first(i->direct_outputs, NULL))) { + pa_assert(o != p); + pa_source_output_kill(o); + p = o; + } + update_n_corked(i, PA_SINK_INPUT_UNLINKED); i->state = PA_SINK_INPUT_UNLINKED; if (linked) if (i->sink->asyncmsgq) - pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL) == 0); reset_callbacks(i); @@ -363,6 +384,7 @@ void pa_sink_input_unlink(pa_sink_input *i) { pa_sink_input_unref(i); } +/* Called from main context */ static void sink_input_free(pa_object *o) { pa_sink_input* i = PA_SINK_INPUT(o); @@ -385,17 +407,27 @@ static void sink_input_free(pa_object *o) { if (i->proplist) pa_proplist_free(i->proplist); + if (i->direct_outputs) + pa_idxset_free(i->direct_outputs, NULL, NULL); + + if (i->thread_info.direct_outputs) + pa_hashmap_free(i->thread_info.direct_outputs, NULL, NULL); + pa_xfree(i->driver); pa_xfree(i); } +/* Called from main context */ void pa_sink_input_put(pa_sink_input *i) { pa_sink_input_state_t state; pa_sink_input_assert_ref(i); pa_assert(i->state == PA_SINK_INPUT_INIT); + + /* The following fields must be initialized properly */ pa_assert(i->pop); pa_assert(i->process_rewind); + pa_assert(i->kill); i->thread_info.volume = i->volume; i->thread_info.muted = i->muted; @@ -405,33 +437,36 @@ void pa_sink_input_put(pa_sink_input *i) { update_n_corked(i, state); i->state = state; - pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL) == 0); pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], i); } +/* Called from main context */ void pa_sink_input_kill(pa_sink_input*i) { pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - if (i->kill) - i->kill(i); + i->kill(i); } -pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { - pa_usec_t r = 0; +/* Called from main context */ +pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) { + pa_usec_t r[2] = { 0, 0 }; pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - if (pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, &r, 0, NULL) < 0) - r = 0; + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0); if (i->get_latency) - r += i->get_latency(i); + r[0] += i->get_latency(i); + + if (sink_latency) + *sink_latency = r[1]; - return r; + return r[0]; } /* Called from thread context */ @@ -684,42 +719,54 @@ void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes /* in the i->update_max_rewind(i, i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, nbytes) : nbytes); } +/* Called from thread context */ +void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */) { + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state)); + pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec)); + + if (i->update_max_request) + i->update_max_request(i, i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, nbytes) : nbytes); +} + +/* Called from thread context */ static pa_usec_t fixup_latency(pa_sink *s, pa_usec_t usec) { pa_sink_assert_ref(s); if (usec == (pa_usec_t) -1) return usec; - if (s->max_latency > 0 && usec > s->max_latency) - usec = s->max_latency; + if (s->thread_info.max_latency > 0 && usec > s->thread_info.max_latency) + usec = s->thread_info.max_latency; - if (s->min_latency > 0 && usec < s->min_latency) - usec = s->min_latency; + if (s->thread_info.min_latency > 0 && usec < s->thread_info.min_latency) + usec = s->thread_info.min_latency; return usec; } +/* Called from thread context */ pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa_usec_t usec) { pa_sink_input_assert_ref(i); usec = fixup_latency(i->sink, usec); - i->thread_info.requested_sink_latency = usec; pa_sink_invalidate_requested_latency(i->sink); return usec; } +/* Called from main context */ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) { pa_sink_input_assert_ref(i); - usec = fixup_latency(i->sink, usec); - if (PA_SINK_INPUT_IS_LINKED(i->state)) - pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL); + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); 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; } @@ -727,13 +774,14 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) return usec; } +/* Called from main context */ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) { pa_usec_t usec = 0; pa_sink_input_assert_ref(i); if (PA_SINK_INPUT_IS_LINKED(i->state)) - pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); else /* If this sink input is not realized yet, we have to touch * the thread info data directly */ @@ -742,19 +790,22 @@ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) { return usec; } +/* Called from main context */ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); + pa_assert(volume); if (pa_cvolume_equal(&i->volume, volume)) return; i->volume = *volume; - pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, NULL, pa_xfree); + 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); } +/* Called from main context */ 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)); @@ -762,6 +813,7 @@ const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) { return &i->volume; } +/* Called from main context */ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute) { pa_assert(i); pa_sink_input_assert_ref(i); @@ -776,13 +828,15 @@ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute) { pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } -int pa_sink_input_get_mute(pa_sink_input *i) { +/* Called from main context */ +pa_bool_t pa_sink_input_get_mute(pa_sink_input *i) { pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - return !!i->muted; + return i->muted; } +/* Called from main context */ void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) { pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); @@ -790,6 +844,7 @@ void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) { sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING); } +/* Called from main context */ int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); @@ -806,6 +861,7 @@ int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { return 0; } +/* Called from main context */ void pa_sink_input_set_name(pa_sink_input *i, const char *name) { const char *old; pa_sink_input_assert_ref(i); @@ -829,16 +885,19 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) { } } +/* Called from main context */ pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { pa_sink_input_assert_ref(i); return i->resample_method; } +/* Called from main context */ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) { pa_resampler *new_resampler; pa_sink *origin; pa_sink_input_move_hook_data hook_data; + pa_source_output *o, *p = NULL; pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); @@ -862,6 +921,13 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) { return -1; } + /* Kill directly connected outputs */ + while ((o = pa_idxset_first(i->direct_outputs, NULL))) { + pa_assert(o != p); + pa_source_output_kill(o); + p = o; + } + if (i->thread_info.resampler && pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) @@ -893,7 +959,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) { hook_data.destination = dest; pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], &hook_data); - pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0); pa_idxset_remove_by_data(origin->inputs, i, NULL); pa_idxset_put(dest->inputs, i, NULL); @@ -927,7 +993,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) { pa_sink_update_status(origin); pa_sink_update_status(dest); - pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0); if (i->moved) i->moved(i); @@ -942,6 +1008,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) { return 0; } +/* Called from IO thread context */ void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state_t state) { pa_sink_input_assert_ref(i); @@ -971,14 +1038,13 @@ void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state i->thread_info.state = state; } -/* Called from thread context */ +/* Called from thread context, except when it is not. */ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { pa_sink_input *i = PA_SINK_INPUT(o); - pa_sink_input_assert_ref(i); - pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state)); switch (code) { + case PA_SINK_INPUT_MESSAGE_SET_VOLUME: i->thread_info.volume = *((pa_cvolume*) userdata); pa_sink_input_request_rewind(i, 0, TRUE, FALSE); @@ -991,8 +1057,13 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t case PA_SINK_INPUT_MESSAGE_GET_LATENCY: { pa_usec_t *r = userdata; + pa_usec_t sink_usec = 0; + + r[0] += pa_bytes_to_usec(pa_memblockq_get_length(i->thread_info.render_memblockq), &i->sink->sample_spec); + + if (i->sink->parent.process_msg(PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_GET_LATENCY, &sink_usec, 0, NULL) >= 0) + r[1] += sink_usec; - *r += pa_bytes_to_usec(pa_memblockq_get_length(i->thread_info.render_memblockq), &i->sink->sample_spec); return 0; } @@ -1017,10 +1088,12 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t return 0; } - case PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY: + case PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY: { + pa_usec_t *usec = userdata; - pa_sink_input_set_requested_latency_within_thread(i, (pa_usec_t) offset); + *usec = pa_sink_input_set_requested_latency_within_thread(i, *usec); return 0; + } case PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY: { pa_usec_t *r = userdata; @@ -1033,6 +1106,7 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t return -1; } +/* Called from main thread */ pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i) { pa_sink_input_assert_ref(i); @@ -1052,6 +1126,7 @@ pa_bool_t pa_sink_input_safe_to_remove(pa_sink_input *i) { return TRUE; } +/* Called from IO context */ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sample spec */, pa_bool_t rewrite, pa_bool_t flush) { size_t lbq; @@ -1111,6 +1186,7 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam pa_sink_request_rewind(i->sink, nbytes - lbq); } +/* Called from main context */ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret) { pa_sink_input_assert_ref(i); pa_assert(ret); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 5f146122..c07a7404 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -1,8 +1,6 @@ #ifndef foopulsesinkinputhfoo #define foopulsesinkinputhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -73,13 +71,19 @@ struct pa_sink_input { pa_sink_input_state_t state; pa_sink_input_flags_t flags; - pa_proplist *proplist; char *driver; /* may be NULL */ + pa_proplist *proplist; + pa_module *module; /* may be NULL */ pa_client *client; /* may be NULL */ pa_sink *sink; + /* A sink input may be connected to multiple source outputs + * directly, so that they don't get mixed data of the entire + * source. */ + pa_idxset *direct_outputs; + pa_sample_spec sample_spec; pa_channel_map channel_map; @@ -109,6 +113,18 @@ struct pa_sink_input { * changes. Called from IO context. */ void (*update_max_rewind) (pa_sink_input *i, size_t nbytes); /* may be NULL */ + /* Called whenever the maxiumum request size of the sink + * changes. Called from IO context. */ + void (*update_max_request) (pa_sink_input *i, size_t nbytes); /* may be NULL */ + + /* Called whenever the configured latency of the sink + * changes. Called from IO context. */ + void (*update_sink_requested_latency) (pa_sink_input *i); /* may be NULL */ + + /* Called whenver the latency range of the sink changes. Called + * from IO context. */ + void (*update_sink_latency_range) (pa_sink_input *i); /* may be NULL */ + /* If non-NULL this function is called when the input is first * connected to a sink or when the rtpoll/asyncmsgq fields * change. You usually don't need to implement this function @@ -130,12 +146,12 @@ struct pa_sink_input { /* Supposed to unlink and destroy this stream. Called from main * context. */ - void (*kill) (pa_sink_input *i); /* may be NULL */ + void (*kill) (pa_sink_input *i); /* may NOT be NULL */ /* Return the current latency (i.e. length of bufferd audio) of - this stream. Called from main context. If NULL a - PA_SINK_INPUT_MESSAGE_GET_LATENCY message is sent to the IO thread - instead. */ + this stream. Called from main context. This is added to what the + PA_SINK_INPUT_MESSAGE_GET_LATENCY message sent to the IO thread + 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 @@ -166,6 +182,8 @@ struct pa_sink_input { /* The requested latency for the sink */ pa_usec_t requested_sink_latency; + + pa_hashmap *direct_outputs; } thread_info; void *userdata; @@ -253,12 +271,12 @@ int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); /* External code may request disconnection with this function */ void pa_sink_input_kill(pa_sink_input*i); -pa_usec_t pa_sink_input_get_latency(pa_sink_input *i); +pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency); void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume); const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i); void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute); -int pa_sink_input_get_mute(pa_sink_input *i); +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); @@ -274,6 +292,7 @@ int pa_sink_input_peek(pa_sink_input *i, size_t length, pa_memchunk *chunk, pa_c void pa_sink_input_drop(pa_sink_input *i, size_t length); void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */); void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */); +void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */); void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state_t state); diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 31c3cfc8..edb023b2 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -105,6 +103,7 @@ void pa_sink_new_data_done(pa_sink_new_data *data) { pa_proplist_free(data->proplist); } +/* Called from main context */ static void reset_callbacks(pa_sink *s) { pa_assert(s); @@ -117,6 +116,7 @@ static void reset_callbacks(pa_sink *s) { s->update_requested_latency = NULL; } +/* Called from main context */ pa_sink* pa_sink_new( pa_core *core, pa_sink_new_data *data, @@ -192,7 +192,7 @@ pa_sink* pa_sink_new( s->volume = data->volume; s->muted = data->muted; - s->refresh_volume = s->refresh_mute = FALSE; + s->refresh_volume = s->refresh_muted = FALSE; reset_callbacks(s); s->userdata = NULL; @@ -207,17 +207,17 @@ pa_sink* pa_sink_new( &s->sample_spec, 0); - s->min_latency = DEFAULT_MIN_LATENCY; - s->max_latency = s->min_latency; - s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - s->thread_info.soft_volume = s->volume; - s->thread_info.soft_muted = s->muted; + pa_cvolume_reset(&s->thread_info.soft_volume, s->sample_spec.channels); + s->thread_info.soft_muted = FALSE; s->thread_info.state = s->state; s->thread_info.rewind_nbytes = 0; s->thread_info.max_rewind = 0; + s->thread_info.max_request = 0; s->thread_info.requested_latency_valid = FALSE; s->thread_info.requested_latency = 0; + s->thread_info.min_latency = DEFAULT_MIN_LATENCY; + s->thread_info.max_latency = 0; pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0); @@ -249,11 +249,14 @@ pa_sink* pa_sink_new( } s->monitor_source->monitor_of = s; + + pa_source_set_latency_range(s->monitor_source, s->thread_info.min_latency, s->thread_info.max_latency); pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind); return s; } +/* Called from main context */ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { int ret; pa_bool_t suspend_change; @@ -272,8 +275,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { return -1; if (s->asyncmsgq) - if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0) - return -1; + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0); s->state = state; @@ -294,18 +296,25 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { return 0; } +/* Called from main context */ void pa_sink_put(pa_sink* s) { pa_sink_assert_ref(s); pa_assert(s->state == PA_SINK_INIT); + + /* The following fields must be initialized properly when calling _put() */ pa_assert(s->asyncmsgq); pa_assert(s->rtpoll); + pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency || + s->thread_info.min_latency <= s->thread_info.max_latency); - pa_assert(!s->min_latency || !s->max_latency || s->min_latency <= s->max_latency); - - if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) + if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) { s->flags |= PA_SINK_DECIBEL_VOLUME; + s->thread_info.soft_volume = s->volume; + s->thread_info.soft_muted = s->muted; + } + pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0); pa_source_put(s->monitor_source); @@ -314,6 +323,7 @@ void pa_sink_put(pa_sink* s) { pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s); } +/* Called from main context */ void pa_sink_unlink(pa_sink* s) { pa_bool_t linked; pa_sink_input *i, *j = NULL; @@ -359,6 +369,7 @@ void pa_sink_unlink(pa_sink* s) { } } +/* Called from main context */ static void sink_free(pa_object *o) { pa_sink *s = PA_SINK(o); pa_sink_input *i; @@ -395,6 +406,7 @@ static void sink_free(pa_object *o) { pa_xfree(s); } +/* Called from main context */ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) { pa_sink_assert_ref(s); @@ -404,6 +416,7 @@ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) { pa_source_set_asyncmsgq(s->monitor_source, q); } +/* Called from main context */ void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) { pa_sink_assert_ref(s); @@ -412,6 +425,7 @@ void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) { pa_source_set_rtpoll(s->monitor_source, p); } +/* Called from main context */ int pa_sink_update_status(pa_sink*s) { pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); @@ -422,6 +436,7 @@ int pa_sink_update_status(pa_sink*s) { return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE); } +/* Called from main context */ int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) { pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); @@ -432,11 +447,12 @@ int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) { return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE); } +/* Called from IO thread context */ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) { pa_sink_input *i; void *state = NULL; pa_sink_assert_ref(s); - pa_assert(PA_SINK_IS_LINKED(s->state)); + pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); /* Make sure the sink code already reset the counter! */ pa_assert(s->thread_info.rewind_nbytes <= 0); @@ -451,11 +467,11 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) { pa_sink_input_process_rewind(i, nbytes); } - if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) + if (s->monitor_source && PA_SOURCE_IS_OPENED(s->monitor_source->thread_info.state)) pa_source_process_rewind(s->monitor_source, nbytes); - } +/* Called from IO thread context */ static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxinfo) { pa_sink_input *i; unsigned n = 0; @@ -495,24 +511,26 @@ static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, uns return n; } -static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length) { +/* Called from IO thread context */ +static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) { pa_sink_input *i; void *state = NULL; unsigned p = 0; unsigned n_unreffed = 0; pa_sink_assert_ref(s); + pa_assert(result); + pa_assert(result->memblock); + pa_assert(result->length > 0); /* We optimize for the case where the order of the inputs has not changed */ while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) { unsigned j; - pa_mix_info* m; + pa_mix_info* m = NULL; pa_sink_input_assert_ref(i); - m = NULL; - /* Let's try to find the matching entry info the pa_mix_info array */ for (j = 0; j < n; j ++) { @@ -527,14 +545,47 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length } /* Drop read data */ - pa_sink_input_drop(i, length); + pa_sink_input_drop(i, result->length); + + if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) { + + if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) { + void *ostate = NULL; + pa_source_output *o; + pa_memchunk c; + + if (m && m->chunk.memblock) { + c = m->chunk; + pa_memblock_ref(c.memblock); + pa_assert(result->length <= c.length); + c.length = result->length; + + pa_memchunk_make_writable(&c, 0); + pa_volume_memchunk(&c, &s->sample_spec, &m->volume); + } else { + c = s->silence; + pa_memblock_ref(c.memblock); + pa_assert(result->length <= c.length); + c.length = result->length; + } + + while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) { + pa_source_output_assert_ref(o); + pa_assert(o->direct_on_input == i); + pa_source_post_direct(s->monitor_source, o, &c); + } + + pa_memblock_unref(c.memblock); + } + } if (m) { - pa_sink_input_unref(m->userdata); - m->userdata = NULL; if (m->chunk.memblock) pa_memblock_unref(m->chunk.memblock); - pa_memchunk_reset(&m->chunk); + pa_memchunk_reset(&m->chunk); + + pa_sink_input_unref(m->userdata); + m->userdata = NULL; n_unreffed += 1; } @@ -551,8 +602,12 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length pa_memblock_unref(info->chunk.memblock); } } + + if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) + pa_source_post(s->monitor_source, result); } +/* Called from IO thread context */ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; @@ -621,14 +676,12 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { } if (s->thread_info.state == PA_SINK_RUNNING) - inputs_drop(s, info, n, result->length); - - if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) - pa_source_post(s->monitor_source, result); + inputs_drop(s, info, n, result); pa_sink_unref(s); } +/* Called from IO thread context */ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; @@ -650,6 +703,8 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) { if (length > block_size_max) length = pa_frame_align(block_size_max, &s->sample_spec); + pa_assert(length > 0); + n = s->thread_info.state == PA_SINK_RUNNING ? fill_mix_info(s, &length, info, MAX_MIX_CHANNELS) : 0; if (n == 0) { @@ -673,8 +728,8 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) { vchunk = info[0].chunk; pa_memblock_ref(vchunk.memblock); - if (vchunk.length > target->length) - vchunk.length = target->length; + if (vchunk.length > length) + vchunk.length = length; if (!pa_cvolume_is_norm(&volume)) { pa_memchunk_make_writable(&vchunk, 0); @@ -700,14 +755,12 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) { } if (s->thread_info.state == PA_SINK_RUNNING) - inputs_drop(s, info, n, target->length); - - if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) - pa_source_post(s->monitor_source, target); + inputs_drop(s, info, n, target); pa_sink_unref(s); } +/* Called from IO thread context */ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { pa_memchunk chunk; size_t l, d; @@ -739,6 +792,7 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { pa_sink_unref(s); } +/* Called from IO thread context */ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_OPENED(s->thread_info.state)); @@ -757,6 +811,7 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { pa_sink_render_into_full(s, result); } +/* Called from main thread */ pa_usec_t pa_sink_get_latency(pa_sink *s) { pa_usec_t usec = 0; @@ -768,14 +823,14 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) { if (!PA_SINK_IS_OPENED(s->state)) return 0; - if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) - return 0; + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0); return usec; } +/* Called from main thread */ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) { - int changed; + pa_bool_t changed; pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); @@ -788,34 +843,36 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) { s->set_volume = NULL; if (!s->set_volume) - pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, NULL, pa_xfree); + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, volume, 0, NULL); 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) { - struct pa_cvolume old_volume; - pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); - old_volume = s->volume; + if (s->refresh_volume) { + struct pa_cvolume old_volume = s->volume; - if (s->get_volume && s->get_volume(s) < 0) - s->get_volume = NULL; + if (s->get_volume && s->get_volume(s) < 0) + s->get_volume = NULL; - if (!s->get_volume && s->refresh_volume) - pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, &s->volume, 0, NULL); + if (!s->get_volume) + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, &s->volume, 0, NULL); - if (!pa_cvolume_equal(&old_volume, &s->volume)) - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + if (!pa_cvolume_equal(&old_volume, &s->volume)) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + } return &s->volume; } +/* Called from main thread */ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) { - int changed; + pa_bool_t changed; pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); @@ -833,26 +890,29 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) { pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } +/* Called from main thread */ pa_bool_t pa_sink_get_mute(pa_sink *s) { - pa_bool_t old_muted; pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); - old_muted = s->muted; + if (s->refresh_muted) { + pa_bool_t old_muted = s->muted; - if (s->get_mute && s->get_mute(s) < 0) - s->get_mute = NULL; + if (s->get_mute && s->get_mute(s) < 0) + s->get_mute = NULL; - if (!s->get_mute && s->refresh_mute) - pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &s->muted, 0, NULL); + if (!s->get_mute) + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &s->muted, 0, NULL); - if (old_muted != s->muted) - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + if (old_muted != s->muted) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + } return s->muted; } +/* Called from main thread */ void pa_sink_set_description(pa_sink *s, const char *description) { const char *old; pa_sink_assert_ref(s); @@ -884,6 +944,7 @@ void pa_sink_set_description(pa_sink *s, const char *description) { } } +/* Called from main thread */ unsigned pa_sink_linked_by(pa_sink *s) { unsigned ret; @@ -901,6 +962,7 @@ unsigned pa_sink_linked_by(pa_sink *s) { return ret; } +/* Called from main thread */ unsigned pa_sink_used_by(pa_sink *s) { unsigned ret; @@ -916,10 +978,10 @@ unsigned pa_sink_used_by(pa_sink *s) { return ret - s->n_corked; } +/* 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); pa_sink_assert_ref(s); - pa_assert(s->thread_info.state != PA_SINK_UNLINKED); switch ((pa_sink_message_t) code) { @@ -957,6 +1019,7 @@ 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); 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); @@ -975,11 +1038,11 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse * sink input handling a few lines down at * PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */ - pa_sink_input_set_state_within_thread(i, i->state); - if (i->detach) i->detach(i); + pa_sink_input_set_state_within_thread(i, i->state); + pa_assert(i->thread_info.attached); i->thread_info.attached = FALSE; @@ -1072,6 +1135,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse i->attach(i); 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); @@ -1122,9 +1186,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse case PA_SINK_MESSAGE_DETACH: - /* We're detaching all our input streams so that the - * asyncmsgq and rtpoll fields can be changed without - * problems */ + /* Detach all streams */ pa_sink_detach_within_thread(s); return 0; @@ -1138,9 +1200,40 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse pa_usec_t *usec = userdata; *usec = pa_sink_get_requested_latency_within_thread(s); + + if (*usec == (pa_usec_t) -1) + *usec = s->thread_info.max_latency; + + return 0; + } + + case PA_SINK_MESSAGE_SET_LATENCY_RANGE: { + pa_usec_t *r = userdata; + + pa_sink_update_latency_range(s, r[0], r[1]); + + return 0; + } + + case PA_SINK_MESSAGE_GET_LATENCY_RANGE: { + pa_usec_t *r = userdata; + + r[0] = s->thread_info.min_latency; + r[1] = s->thread_info.max_latency; + return 0; } + case PA_SINK_MESSAGE_GET_MAX_REWIND: + + *((size_t*) userdata) = s->thread_info.max_rewind; + return 0; + + case PA_SINK_MESSAGE_GET_MAX_REQUEST: + + *((size_t*) userdata) = s->thread_info.max_request; + return 0; + case PA_SINK_MESSAGE_GET_LATENCY: case PA_SINK_MESSAGE_MAX: ; @@ -1149,6 +1242,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse return -1; } +/* Called from main thread */ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) { pa_sink *sink; uint32_t idx; @@ -1162,20 +1256,23 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) { return ret; } +/* Called from main thread */ void pa_sink_detach(pa_sink *s) { pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); - pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0); } +/* Called from main thread */ void pa_sink_attach(pa_sink *s) { pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); - pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0); } +/* Called from IO thread */ void pa_sink_detach_within_thread(pa_sink *s) { pa_sink_input *i; void *state = NULL; @@ -1191,6 +1288,7 @@ void pa_sink_detach_within_thread(pa_sink *s) { pa_source_detach_within_thread(s->monitor_source); } +/* Called from IO thread */ void pa_sink_attach_within_thread(pa_sink *s) { pa_sink_input *i; void *state = NULL; @@ -1206,6 +1304,7 @@ void pa_sink_attach_within_thread(pa_sink *s) { pa_source_attach_within_thread(s->monitor_source); } +/* Called from IO thread */ void pa_sink_request_rewind(pa_sink*s, size_t nbytes) { pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); @@ -1224,10 +1323,12 @@ void pa_sink_request_rewind(pa_sink*s, size_t nbytes) { s->request_rewind(s); } +/* Called from IO thread */ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) { pa_usec_t result = (pa_usec_t) -1; pa_sink_input *i; void *state = NULL; + pa_usec_t monitor_latency; pa_sink_assert_ref(s); @@ -1240,12 +1341,18 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) { (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency)) result = i->thread_info.requested_sink_latency; + monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source); + + if (monitor_latency != (pa_usec_t) -1 && + (result == (pa_usec_t) -1 || result > monitor_latency)) + result = monitor_latency; + if (result != (pa_usec_t) -1) { - if (s->max_latency > 0 && result > s->max_latency) - result = s->max_latency; + if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency) + result = s->thread_info.max_latency; - if (s->min_latency > 0 && result < s->min_latency) - result = s->min_latency; + if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency) + result = s->thread_info.min_latency; } s->thread_info.requested_latency = result; @@ -1254,6 +1361,7 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) { return result; } +/* Called from main thread */ pa_usec_t pa_sink_get_requested_latency(pa_sink *s) { pa_usec_t usec = 0; @@ -1263,15 +1371,11 @@ pa_usec_t pa_sink_get_requested_latency(pa_sink *s) { if (!PA_SINK_IS_OPENED(s->state)) return 0; - if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) < 0) - return 0; - - if (usec == (pa_usec_t) -1) - usec = s->max_latency; - + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); return usec; } +/* Called from IO thread */ void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) { pa_sink_input *i; void *state = NULL; @@ -1283,20 +1387,145 @@ void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) { s->thread_info.max_rewind = max_rewind; - while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) - pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind); + if (PA_SINK_IS_LINKED(s->thread_info.state)) { + while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind); + } if (s->monitor_source) pa_source_set_max_rewind(s->monitor_source, s->thread_info.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); + + if (max_request == s->thread_info.max_request) + return; + + s->thread_info.max_request = max_request; + + if (PA_SINK_IS_LINKED(s->thread_info.state)) { + while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + pa_sink_input_update_max_request(i, s->thread_info.max_request); + } +} + +/* Called from IO thread */ void pa_sink_invalidate_requested_latency(pa_sink *s) { + pa_sink_input *i; + void *state = NULL; pa_sink_assert_ref(s); - pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); s->thread_info.requested_latency_valid = FALSE; if (s->update_requested_latency) s->update_requested_latency(s); + + while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + if (i->update_sink_requested_latency) + i->update_sink_requested_latency(i); +} + +/* Called from main thread */ +void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) { + pa_sink_assert_ref(s); + + /* min_latency == 0: no limit + * min_latency == (size_t) -1: default limit + * min_latency anything else: specified limit + * + * Similar for max_latency */ + + if (min_latency == (pa_usec_t) -1) + min_latency = DEFAULT_MIN_LATENCY; + + if (max_latency == (pa_usec_t) -1) + max_latency = min_latency; + + pa_assert(!min_latency || !max_latency || + min_latency <= max_latency); + + if (PA_SINK_IS_LINKED(s->state)) { + pa_usec_t r[2]; + + r[0] = min_latency; + r[1] = max_latency; + + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0); + } else { + s->thread_info.min_latency = min_latency; + s->thread_info.max_latency = max_latency; + + s->monitor_source->thread_info.min_latency = min_latency; + s->monitor_source->thread_info.max_latency = max_latency; + + s->thread_info.requested_latency_valid = s->monitor_source->thread_info.requested_latency_valid = FALSE; + } +} + +/* Called from main thread */ +void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) { + pa_sink_assert_ref(s); + pa_assert(min_latency); + pa_assert(max_latency); + + if (PA_SINK_IS_LINKED(s->state)) { + pa_usec_t r[2] = { 0, 0 }; + + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0); + + *min_latency = r[0]; + *max_latency = r[1]; + } else { + *min_latency = s->thread_info.min_latency; + *max_latency = s->thread_info.max_latency; + } +} + +/* Called from IO thread */ +void pa_sink_update_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) { + pa_sink_input *i; + void *state = NULL; + + pa_sink_assert_ref(s); + + s->thread_info.min_latency = min_latency; + s->thread_info.max_latency = max_latency; + + while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + if (i->update_sink_latency_range) + i->update_sink_latency_range(i); + + pa_sink_invalidate_requested_latency(s); + + pa_source_update_latency_range(s->monitor_source, min_latency, max_latency); +} + +size_t pa_sink_get_max_rewind(pa_sink *s) { + size_t r; + pa_sink_assert_ref(s); + + if (!PA_SINK_IS_LINKED(s->state)) + return s->thread_info.max_rewind; + + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0); + + return r; +} + +size_t pa_sink_get_max_request(pa_sink *s) { + size_t r; + pa_sink_assert_ref(s); + + if (!PA_SINK_IS_LINKED(s->state)) + return s->thread_info.max_request; + + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0); + + return r; } diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index f297c8f1..b73944e8 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -1,8 +1,6 @@ #ifndef foopulsesinkhfoo #define foopulsesinkhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -82,17 +80,15 @@ struct pa_sink { pa_cvolume volume; pa_bool_t muted; - pa_bool_t refresh_volume; - pa_bool_t refresh_mute; + + pa_bool_t refresh_volume:1; + pa_bool_t refresh_muted:1; pa_asyncmsgq *asyncmsgq; pa_rtpoll *rtpoll; pa_memchunk silence; - pa_usec_t min_latency; /* we won't go below this latency */ - pa_usec_t max_latency; /* An upper limit for the latencies */ - /* Called when the main loop requests a state change. Called from * main loop context. If returns -1 the state change will be * inhibited */ @@ -100,8 +96,9 @@ struct pa_sink { /* Callled when the volume is queried. Called from main loop * context. If this is NULL a PA_SINK_MESSAGE_GET_VOLUME message - * will be sent to the IO thread instead. */ - int (*get_volume)(pa_sink *s); /* may be null */ + * will be sent to the IO thread instead. If refresh_volume is + * FALSE neither this function is called nor a message is sent. */ + int (*get_volume)(pa_sink *s); /* may be NULL */ /* Called when the volume shall be changed. Called from main loop * context. If this is NULL a PA_SINK_MESSAGE_SET_VOLUME message @@ -110,7 +107,8 @@ struct pa_sink { /* Called when the mute setting is queried. Called from main loop * context. If this is NULL a PA_SINK_MESSAGE_GET_MUTE message - * will be sent to the IO thread instead. */ + * will be sent to the IO thread instead. If refresh_mute is + * FALSE neither this function is called nor a message is sent.*/ int (*get_mute)(pa_sink *s); /* dito */ /* Called when the mute setting shall be changed. Called from main @@ -132,17 +130,24 @@ struct pa_sink { pa_sink_state_t state; pa_hashmap *inputs; pa_cvolume soft_volume; - pa_bool_t soft_muted; + pa_bool_t soft_muted:1; - pa_bool_t requested_latency_valid; + pa_bool_t requested_latency_valid:1; pa_usec_t requested_latency; - /* The number of bytes we need keep around to be able to satisfy - * every DMA buffer rewrite */ + /* The number of bytes streams need to keep around as history to + * be able to satisfy every DMA buffer rewrite */ size_t max_rewind; + /* The number of bytes streams need to keep around to satisfy + * every DMA write request */ + size_t max_request; + /* Maximum of what clients requested to rewind in this cycle */ size_t rewind_nbytes; + + pa_usec_t min_latency; /* we won't go below this latency */ + pa_usec_t max_latency; /* An upper limit for the latencies */ } thread_info; void *userdata; @@ -165,6 +170,10 @@ typedef enum pa_sink_message { PA_SINK_MESSAGE_FINISH_MOVE, PA_SINK_MESSAGE_ATTACH, PA_SINK_MESSAGE_DETACH, + PA_SINK_MESSAGE_SET_LATENCY_RANGE, + PA_SINK_MESSAGE_GET_LATENCY_RANGE, + PA_SINK_MESSAGE_GET_MAX_REWIND, + PA_SINK_MESSAGE_GET_MAX_REQUEST, PA_SINK_MESSAGE_MAX } pa_sink_message_t; @@ -209,6 +218,8 @@ void pa_sink_set_description(pa_sink *s, const char *description); void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q); void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p); +void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency); + void pa_sink_detach(pa_sink *s); void pa_sink_attach(pa_sink *s); @@ -217,6 +228,10 @@ void pa_sink_attach(pa_sink *s); /* The returned value is supposed to be in the time domain of the sound card! */ pa_usec_t pa_sink_get_latency(pa_sink *s); pa_usec_t pa_sink_get_requested_latency(pa_sink *s); +void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency); + +size_t pa_sink_get_max_rewind(pa_sink *s); +size_t pa_sink_get_max_request(pa_sink *s); int pa_sink_update_status(pa_sink*s); int pa_sink_suspend(pa_sink *s, pa_bool_t suspend); @@ -248,6 +263,9 @@ void pa_sink_detach_within_thread(pa_sink *s); pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s); void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind); +void pa_sink_set_max_request(pa_sink *s, size_t max_request); + +void pa_sink_update_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency); /* To be called exclusively by sink input drivers, from IO context */ diff --git a/src/pulsecore/sioman.c b/src/pulsecore/sioman.c index 8d4c6fa7..7e5b186c 100644 --- a/src/pulsecore/sioman.c +++ b/src/pulsecore/sioman.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/sioman.h b/src/pulsecore/sioman.h index 49fffb34..d0cacc9b 100644 --- a/src/pulsecore/sioman.h +++ b/src/pulsecore/sioman.h @@ -1,8 +1,6 @@ #ifndef foosiomanhfoo #define foosiomanhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c index a99193b7..e69a63da 100644 --- a/src/pulsecore/socket-client.c +++ b/src/pulsecore/socket-client.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -61,6 +59,7 @@ #include <pulsecore/core-error.h> #include <pulsecore/socket-util.h> #include <pulsecore/core-util.h> +#include <pulsecore/socket-util.h> #include <pulsecore/log.h> #include <pulsecore/parseaddr.h> #include <pulsecore/macro.h> @@ -270,22 +269,7 @@ static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size pa_assert(sa); pa_assert(salen); - switch (sa->sa_family) { - case AF_UNIX: - c->local = TRUE; - break; - - case AF_INET: - c->local = ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK; - break; - - case AF_INET6: - c->local = memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0; - break; - - default: - c->local = FALSE; - } + c->local = pa_socket_address_is_local(sa); if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { pa_log("socket(): %s", pa_cstrerror(errno)); diff --git a/src/pulsecore/socket-client.h b/src/pulsecore/socket-client.h index 41e8c3bd..9ceeaddc 100644 --- a/src/pulsecore/socket-client.h +++ b/src/pulsecore/socket-client.h @@ -1,8 +1,6 @@ #ifndef foosocketclienthfoo #define foosocketclienthfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index 162a1aac..9885a02b 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -83,7 +81,7 @@ struct pa_socket_server { char *filename; char *tcpwrap_service; - void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata); + pa_socket_server_on_connection_cb_t on_connection; void *userdata; pa_io_event *io_event; @@ -91,7 +89,7 @@ struct pa_socket_server { enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type; }; -static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { +static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_socket_server *s = userdata; pa_iochannel *io; int nfd; @@ -195,9 +193,9 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file pa_make_fd_cloexec(fd); + memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1); - sa.sun_path[sizeof(sa.sun_path) - 1] = 0; + pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path)); pa_make_socket_low_delay(fd); @@ -295,7 +293,7 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad pa_socket_server *ss; int fd = -1; struct sockaddr_in6 sa; - int on = 1; + int on; pa_assert(m); pa_assert(port > 0); @@ -308,11 +306,13 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad pa_make_fd_cloexec(fd); #ifdef IPV6_V6ONLY + on = 1; if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) pa_log("setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno)); #endif #ifdef SO_REUSEADDR + on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) pa_log("setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno)); #endif @@ -426,7 +426,7 @@ void pa_socket_server_unref(pa_socket_server *s) { socket_server_free(s); } -void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata) { +void pa_socket_server_set_callback(pa_socket_server*s, pa_socket_server_on_connection_cb_t on_connection, void *userdata) { pa_assert(s); pa_assert(PA_REFCNT_VALUE(s) >= 1); @@ -507,7 +507,6 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { } pa_snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port)); - } return c; diff --git a/src/pulsecore/socket-server.h b/src/pulsecore/socket-server.h index 777599e5..1edfb432 100644 --- a/src/pulsecore/socket-server.h +++ b/src/pulsecore/socket-server.h @@ -1,8 +1,6 @@ #ifndef foosocketserverhfoo #define foosocketserverhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -47,7 +45,9 @@ pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const cha void pa_socket_server_unref(pa_socket_server*s); pa_socket_server* pa_socket_server_ref(pa_socket_server *s); -void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata); +typedef void (*pa_socket_server_on_connection_cb_t)(pa_socket_server*s, pa_iochannel *io, void *userdata); + +void pa_socket_server_set_callback(pa_socket_server*s, pa_socket_server_on_connection_cb_t connection_cb, void *userdata); char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l); diff --git a/src/pulsecore/socket-util.c b/src/pulsecore/socket-util.c index 456accb8..f721f699 100644 --- a/src/pulsecore/socket-util.c +++ b/src/pulsecore/socket-util.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -129,8 +127,8 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) { return; #endif } - } + #ifndef OS_IS_WIN32 pa_snprintf(c, l, "Unknown network client"); return; @@ -284,3 +282,40 @@ int pa_unix_socket_remove_stale(const char *fn) { } #endif /* HAVE_SYS_UN_H */ + + +pa_bool_t pa_socket_address_is_local(const struct sockaddr *sa) { + pa_assert(sa); + + switch (sa->sa_family) { + case AF_UNIX: + return TRUE; + + case AF_INET: + return ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK; + + case AF_INET6: + return memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0; + + default: + return FALSE; + } +} + +pa_bool_t pa_socket_is_local(int fd) { + + union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; +#ifdef HAVE_SYS_UN_H + struct sockaddr_un un; +#endif + } sa; + socklen_t sa_len = sizeof(sa); + + if (getpeername(fd, &sa.sa, &sa_len) < 0) + return FALSE; + + return pa_socket_address_is_local(&sa.sa); +} diff --git a/src/pulsecore/socket-util.h b/src/pulsecore/socket-util.h index a0344c68..7a40285a 100644 --- a/src/pulsecore/socket-util.h +++ b/src/pulsecore/socket-util.h @@ -1,8 +1,6 @@ #ifndef foosocketutilhfoo #define foosocketutilhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -26,6 +24,9 @@ ***/ #include <sys/types.h> +#include <sys/socket.h> + +#include <pulsecore/macro.h> void pa_socket_peer_to_string(int fd, char *c, size_t l); @@ -39,4 +40,7 @@ int pa_socket_set_rcvbuf(int fd, size_t l); int pa_unix_socket_is_stale(const char *fn); int pa_unix_socket_remove_stale(const char *fn); +pa_bool_t pa_socket_address_is_local(const struct sockaddr *sa); +pa_bool_t pa_socket_is_local(int fd); + #endif diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index e209676f..8eedf830 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -35,6 +33,7 @@ #include <sndfile.h> #include <pulse/xmalloc.h> +#include <pulse/util.h> #include <pulsecore/core-error.h> #include <pulsecore/sink-input.h> @@ -149,8 +148,6 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk if (!u->memblockq) return -1; - pa_log_debug("pop: %lu", (unsigned long) length); - for (;;) { pa_memchunk tchunk; size_t fs; @@ -158,6 +155,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk sf_count_t n; if (pa_memblockq_peek(u->memblockq, chunk) >= 0) { + chunk->length = PA_MIN(chunk->length, length); pa_memblockq_drop(u->memblockq, chunk->length); return 0; } @@ -194,11 +192,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk pa_memblock_unref(tchunk.memblock); } - pa_log_debug("peek fail"); - if (pa_sink_input_safe_to_remove(i)) { - pa_log_debug("completed to play"); - pa_memblockq_free(u->memblockq); u->memblockq = NULL; @@ -216,6 +210,8 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) { u = FILE_STREAM(i->userdata); file_stream_assert_ref(u); + pa_log("backwards %lu", (unsigned long) nbytes); + if (!u->memblockq) return; @@ -330,7 +326,7 @@ int pa_play_file( data.driver = __FILE__; pa_sink_input_new_data_set_sample_spec(&data, &ss); pa_sink_input_new_data_set_volume(&data, volume); - pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, fname); + pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, pa_path_get_filename(fname)); pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname); u->sink_input = pa_sink_input_new(sink->core, &data, 0); diff --git a/src/pulsecore/sound-file-stream.h b/src/pulsecore/sound-file-stream.h index 189e242d..4cc69146 100644 --- a/src/pulsecore/sound-file-stream.h +++ b/src/pulsecore/sound-file-stream.h @@ -1,8 +1,6 @@ #ifndef foosoundfilestreamhfoo #define foosoundfilestreamhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c index 3e6f683d..3183ede6 100644 --- a/src/pulsecore/sound-file.c +++ b/src/pulsecore/sound-file.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -119,10 +117,7 @@ int pa_sound_file_load( } if (map) - if (!pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_DEFAULT)) { - pa_log("Unsupported channel map in file %s", fname); - goto finish; - } + 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) { pa_log("File too large"); diff --git a/src/pulsecore/sound-file.h b/src/pulsecore/sound-file.h index 46763bd8..e4d703d3 100644 --- a/src/pulsecore/sound-file.h +++ b/src/pulsecore/sound-file.h @@ -1,8 +1,6 @@ #ifndef soundfilehfoo #define soundfilehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 5c36937a..3d1abe30 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -76,12 +74,15 @@ void pa_source_output_new_data_done(pa_source_output_new_data *data) { pa_proplist_free(data->proplist); } +/* Called from main context */ static void reset_callbacks(pa_source_output *o) { pa_assert(o); o->push = NULL; o->process_rewind = NULL; o->update_max_rewind = NULL; + o->update_source_requested_latency = NULL; + o->update_source_latency_range = NULL; o->attach = NULL; o->detach = NULL; o->suspend = NULL; @@ -91,6 +92,7 @@ static void reset_callbacks(pa_source_output *o) { o->state_change = NULL; } +/* Called from main context */ pa_source_output* pa_source_output_new( pa_core *core, pa_source_output_new_data *data, @@ -109,11 +111,13 @@ pa_source_output* pa_source_output_new( pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver)); if (!data->source) - data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, 1); + data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, TRUE); pa_return_null_if_fail(data->source); pa_return_null_if_fail(pa_source_get_state(data->source) != PA_SOURCE_UNLINKED); + pa_return_null_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of); + if (!data->sample_spec_is_set) data->sample_spec = data->source->sample_spec; @@ -192,6 +196,8 @@ pa_source_output* pa_source_output_new( o->sample_spec = data->sample_spec; o->channel_map = data->channel_map; + o->direct_on_input = data->direct_on_input; + reset_callbacks(o); o->userdata = NULL; @@ -200,6 +206,7 @@ pa_source_output* pa_source_output_new( o->thread_info.sample_spec = o->sample_spec; o->thread_info.resampler = resampler; o->thread_info.requested_source_latency = (pa_usec_t) -1; + o->thread_info.direct_on_input = o->direct_on_input; o->thread_info.delay_memblockq = pa_memblockq_new( 0, @@ -214,6 +221,9 @@ pa_source_output* pa_source_output_new( pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0); pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0); + if (o->direct_on_input) + pa_assert_se(pa_idxset_put(o->direct_on_input->direct_outputs, o, NULL) == 0); + pa_log_info("Created output %u \"%s\" on %s with sample spec %s and channel map %s", o->index, pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME)), @@ -226,6 +236,7 @@ pa_source_output* pa_source_output_new( return o; } +/* Called from main context */ static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) { pa_assert(o); @@ -237,14 +248,14 @@ static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) pa_source_update_status(o->source); } +/* Called from main context */ static int source_output_set_state(pa_source_output *o, pa_source_output_state_t state) { pa_assert(o); if (o->state == state) return 0; - if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0) - return -1; + pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0); update_n_corked(o, state); o->state = state; @@ -255,6 +266,7 @@ static int source_output_set_state(pa_source_output *o, pa_source_output_state_t return 0; } +/* Called from main context */ void pa_source_output_unlink(pa_source_output*o) { pa_bool_t linked; pa_assert(o); @@ -269,6 +281,8 @@ void pa_source_output_unlink(pa_source_output*o) { if (linked) pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o); + if (o->direct_on_input) + pa_idxset_remove_by_data(o->direct_on_input->direct_outputs, o, NULL); pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); if (pa_idxset_remove_by_data(o->source->outputs, o, NULL)) pa_source_output_unref(o); @@ -278,7 +292,7 @@ void pa_source_output_unlink(pa_source_output*o) { if (linked) if (o->source->asyncmsgq) - pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0); reset_callbacks(o); @@ -291,6 +305,7 @@ void pa_source_output_unlink(pa_source_output*o) { pa_source_output_unref(o); } +/* Called from main context */ static void source_output_free(pa_object* mo) { pa_source_output *o = PA_SOURCE_OUTPUT(mo); @@ -317,45 +332,52 @@ static void source_output_free(pa_object* mo) { pa_xfree(o); } +/* Called from main context */ void pa_source_output_put(pa_source_output *o) { pa_source_output_state_t state; pa_source_output_assert_ref(o); pa_assert(o->state == PA_SOURCE_OUTPUT_INIT); + + /* The following fields must be initialized properly */ pa_assert(o->push); + pa_assert(o->kill); state = o->flags & PA_SOURCE_OUTPUT_START_CORKED ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; update_n_corked(o, state); o->state = state; - pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0); pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index); pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], o); } +/* Called from main context */ void pa_source_output_kill(pa_source_output*o) { pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); - if (o->kill) - o->kill(o); + o->kill(o); } -pa_usec_t pa_source_output_get_latency(pa_source_output *o) { - pa_usec_t r = 0; +/* Called from main context */ +pa_usec_t pa_source_output_get_latency(pa_source_output *o, pa_usec_t *source_latency) { + pa_usec_t r[2] = { 0, 0 }; pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); - if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, &r, 0, NULL) < 0) - r = 0; + pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0); if (o->get_latency) - r += o->get_latency(o); + r[0] += o->get_latency(o); - return r; + if (source_latency) + *source_latency = r[1]; + + return r[0]; } /* Called from thread context */ @@ -368,10 +390,10 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { pa_assert(chunk); pa_assert(pa_frame_aligned(chunk->length, &o->source->sample_spec)); - if (!o->push || o->state == PA_SOURCE_OUTPUT_CORKED) + if (!o->push || o->thread_info.state == PA_SOURCE_OUTPUT_CORKED) return; - pa_assert(o->state == PA_SOURCE_OUTPUT_RUNNING); + pa_assert(o->thread_info.state == PA_SOURCE_OUTPUT_RUNNING); if (pa_memblockq_push(o->thread_info.delay_memblockq, chunk) < 0) { pa_log_debug("Delay queue overflow!"); @@ -409,7 +431,8 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { if (rchunk.length > 0) o->push(o, &rchunk); - pa_memblock_unref(rchunk.memblock); + if (rchunk.memblock) + pa_memblock_unref(rchunk.memblock); } pa_memblock_unref(qchunk.memblock); @@ -421,7 +444,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in sink sample spec */) { pa_source_output_assert_ref(o); - pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); + pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state)); pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec)); if (nbytes <= 0) @@ -455,42 +478,44 @@ void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* i o->update_max_rewind(o, o->thread_info.resampler ? pa_resampler_result(o->thread_info.resampler, nbytes) : nbytes); } +/* Called from thread context */ static pa_usec_t fixup_latency(pa_source *s, pa_usec_t usec) { pa_source_assert_ref(s); if (usec == (pa_usec_t) -1) return usec; - if (s->max_latency > 0 && usec > s->max_latency) - usec = s->max_latency; + if (s->thread_info.max_latency > 0 && usec > s->thread_info.max_latency) + usec = s->thread_info.max_latency; - if (s->min_latency > 0 && usec < s->min_latency) - usec = s->min_latency; + if (s->thread_info.min_latency > 0 && usec < s->thread_info.min_latency) + usec = s->thread_info.min_latency; return usec; } +/* Called from thread context */ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec) { pa_source_output_assert_ref(o); usec = fixup_latency(o->source, usec); - o->thread_info.requested_source_latency = usec; pa_source_invalidate_requested_latency(o->source); return usec; } +/* Called from main context */ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) { pa_source_output_assert_ref(o); - usec = fixup_latency(o->source, usec); - if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) - pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL); + pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); else { /* If this sink input 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; } @@ -498,13 +523,14 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t return usec; } +/* Called from main context */ pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) { pa_usec_t usec = 0; pa_source_output_assert_ref(o); if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) - pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); else /* If this sink input is not realized yet, we have to touch * the thread info data directly */ @@ -513,6 +539,7 @@ pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) { return usec; } +/* Called from main context */ void pa_source_output_cork(pa_source_output *o, pa_bool_t b) { pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); @@ -520,6 +547,7 @@ void pa_source_output_cork(pa_source_output *o, pa_bool_t b) { source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING); } +/* Called from main context */ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) { pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); @@ -536,6 +564,7 @@ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) { return 0; } +/* Called from main context */ void pa_source_output_set_name(pa_source_output *o, const char *name) { const char *old; pa_source_output_assert_ref(o); @@ -559,12 +588,14 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) { } } +/* Called from main context */ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { pa_source_output_assert_ref(o); return o->resample_method; } +/* Called from main context */ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_source *origin; pa_resampler *new_resampler; @@ -582,6 +613,9 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE) 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; @@ -619,7 +653,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], &hook_data); /* Okey, let's move it */ - pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0); pa_idxset_remove_by_data(origin->outputs, o, NULL); pa_idxset_put(dest->outputs, o, NULL); @@ -652,7 +686,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_source_update_status(origin); pa_source_update_status(dest); - pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0); if (o->moved) o->moved(o); @@ -667,6 +701,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { return 0; } +/* Called from IO thread context */ void pa_source_output_set_state_within_thread(pa_source_output *o, pa_source_output_state_t state) { pa_source_output_assert_ref(o); @@ -679,19 +714,22 @@ void pa_source_output_set_state_within_thread(pa_source_output *o, pa_source_out o->thread_info.state = state; } -/* Called from thread context */ +/* Called from IO thread context, except when it is not */ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int64_t offset, pa_memchunk* chunk) { pa_source_output *o = PA_SOURCE_OUTPUT(mo); - pa_source_output_assert_ref(o); - pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state)); switch (code) { case PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY: { pa_usec_t *r = userdata; + pa_usec_t source_usec = 0; + + r[0] += pa_bytes_to_usec(pa_memblockq_get_length(o->thread_info.delay_memblockq), &o->source->sample_spec); + + if (o->source->parent.process_msg(PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_GET_LATENCY, &source_usec, 0, NULL) >= 0) + r[1] += source_usec; - *r += pa_bytes_to_usec(pa_memblockq_get_length(o->thread_info.delay_memblockq), &o->source->sample_spec); return 0; } @@ -706,10 +744,13 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int pa_source_output_set_state_within_thread(o, PA_PTR_TO_UINT(userdata)); return 0; - case PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY: + case PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY: { + pa_usec_t *usec = userdata; + + *usec = pa_source_output_set_requested_latency_within_thread(o, *usec); - pa_source_output_set_requested_latency_within_thread(o, (pa_usec_t) offset); return 0; + } case PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY: { pa_usec_t *r = userdata; diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 2dadb5c4..61825b22 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -1,8 +1,6 @@ #ifndef foopulsesourceoutputhfoo #define foopulsesourceoutputhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -66,13 +64,17 @@ struct pa_source_output { pa_source_output_state_t state; pa_source_output_flags_t flags; - pa_proplist *proplist; char *driver; /* may be NULL */ + pa_proplist *proplist; + pa_module *module; /* may be NULL */ pa_client *client; /* may be NULL */ pa_source *source; + /* A source output can monitor just a single input of a sink, in which case we find it here */ + pa_sink_input *direct_on_input; /* may be NULL */ + pa_sample_spec sample_spec; pa_channel_map channel_map; @@ -80,16 +82,24 @@ struct pa_source_output { /* Pushes a new memchunk into the output. Called from IO thread * context. */ - void (*push)(pa_source_output *o, const pa_memchunk *chunk); + void (*push)(pa_source_output *o, const pa_memchunk *chunk); /* may NOT be NULL */ /* Only relevant for monitor sources right now: called when the - * recorded stream is rewound. Called from IO context*/ - void (*process_rewind)(pa_source_output *o, size_t nbytes); + * recorded stream is rewound. Called from IO context */ + void (*process_rewind)(pa_source_output *o, size_t nbytes); /* may be NULL */ /* Called whenever the maximum rewindable size of the source * changes. Called from IO thread context. */ void (*update_max_rewind) (pa_source_output *o, size_t nbytes); /* may be NULL */ + /* Called whenever the configured latency of the source + * changes. Called from IO context. */ + void (*update_source_requested_latency) (pa_source_output *o); /* may be NULL */ + + /* Called whenver the latency range of the source changes. Called + * from IO context. */ + void (*update_source_latency_range) (pa_source_output *o); /* may be NULL */ + /* If non-NULL this function is called when the output is first * connected to a source. Called from IO thread context */ void (*attach) (pa_source_output *o); /* may be NULL */ @@ -108,12 +118,12 @@ struct pa_source_output { /* Supposed to unlink and destroy this stream. Called from main * context. */ - void (*kill)(pa_source_output* o); /* may be NULL */ + void (*kill)(pa_source_output* o); /* may NOT be NULL */ /* Return the current latency (i.e. length of bufferd audio) of - this stream. Called from main context. If NULL a - PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY message is sent to the IO - thread instead. */ + this stream. Called from main context. This is added to what the + PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY message sent to the IO thread + 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 @@ -135,6 +145,8 @@ struct pa_source_output { /* The requested latency for the source */ pa_usec_t requested_source_latency; + + pa_sink_input *direct_on_input; /* may be NULL */ } thread_info; void *userdata; @@ -154,6 +166,7 @@ enum { typedef struct pa_source_output_new_data { pa_proplist *proplist; + pa_sink_input *direct_on_input; const char *driver; pa_module *module; @@ -202,7 +215,7 @@ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate); /* External code may request disconnection with this funcion */ void pa_source_output_kill(pa_source_output*o); -pa_usec_t pa_source_output_get_latency(pa_source_output *i); +pa_usec_t pa_source_output_get_latency(pa_source_output *i, pa_usec_t *source_latency); pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o); diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index c767abcf..8256a988 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -99,6 +97,7 @@ void pa_source_new_data_done(pa_source_new_data *data) { pa_proplist_free(data->proplist); } +/* Called from main context */ static void reset_callbacks(pa_source *s) { pa_assert(s); @@ -110,6 +109,7 @@ static void reset_callbacks(pa_source *s) { s->update_requested_latency = NULL; } +/* Called from main context */ pa_source* pa_source_new( pa_core *core, pa_source_new_data *data, @@ -120,6 +120,8 @@ pa_source* pa_source_new( char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_assert(core); + pa_assert(data); + pa_assert(data->name); s = pa_msgobject_new(pa_source); @@ -128,6 +130,8 @@ pa_source* pa_source_new( return NULL; } + pa_source_new_data_set_name(data, name); + if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) { pa_xfree(s); pa_namereg_unregister(core, name); @@ -195,16 +199,15 @@ pa_source* pa_source_new( &s->sample_spec, 0); - s->min_latency = DEFAULT_MIN_LATENCY; - s->max_latency = s->min_latency; - s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - s->thread_info.soft_volume = s->volume; - s->thread_info.soft_muted = s->muted; + pa_cvolume_reset(&s->thread_info.soft_volume, s->sample_spec.channels); + s->thread_info.soft_muted = FALSE; s->thread_info.state = s->state; s->thread_info.max_rewind = 0; s->thread_info.requested_latency_valid = FALSE; s->thread_info.requested_latency = 0; + s->thread_info.min_latency = DEFAULT_MIN_LATENCY; + s->thread_info.max_latency = 0; pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0); @@ -217,6 +220,7 @@ pa_source* pa_source_new( return s; } +/* Called from main context */ static int source_set_state(pa_source *s, pa_source_state_t state) { int ret; pa_bool_t suspend_change; @@ -235,8 +239,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state) { return -1; if (s->asyncmsgq) - if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0) - return -1; + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0); s->state = state; @@ -257,24 +260,32 @@ static int source_set_state(pa_source *s, pa_source_state_t state) { return 0; } +/* Called from main context */ void pa_source_put(pa_source *s) { pa_source_assert_ref(s); pa_assert(s->state == PA_SINK_INIT); + + /* The following fields must be initialized properly when calling _put() */ pa_assert(s->asyncmsgq); pa_assert(s->rtpoll); + pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency || + s->thread_info.min_latency <= s->thread_info.max_latency); - pa_assert(!s->min_latency || !s->max_latency || s->min_latency <= s->max_latency); - - if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL)) + if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL)) { s->flags |= PA_SOURCE_DECIBEL_VOLUME; + s->thread_info.soft_volume = s->volume; + s->thread_info.soft_muted = s->muted; + } + pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0); pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s); } +/* Called from main context */ void pa_source_unlink(pa_source *s) { pa_bool_t linked; pa_source_output *o, *j = NULL; @@ -312,6 +323,7 @@ void pa_source_unlink(pa_source *s) { } } +/* Called from main context */ static void source_free(pa_object *o) { pa_source_output *so; pa_source *s = PA_SOURCE(o); @@ -343,18 +355,21 @@ static void source_free(pa_object *o) { pa_xfree(s); } +/* Called from main context */ void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) { pa_source_assert_ref(s); s->asyncmsgq = q; } +/* Called from main context */ void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) { pa_source_assert_ref(s); s->rtpoll = p; } +/* Called from main context */ int pa_source_update_status(pa_source*s) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); @@ -365,6 +380,7 @@ int pa_source_update_status(pa_source*s) { return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE); } +/* Called from main context */ int pa_source_suspend(pa_source *s, pa_bool_t suspend) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); @@ -375,6 +391,7 @@ int pa_source_suspend(pa_source *s, pa_bool_t suspend) { return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE); } +/* Called from IO thread context */ void pa_source_process_rewind(pa_source *s, size_t nbytes) { pa_source_output *o; void *state = NULL; @@ -393,6 +410,7 @@ void pa_source_process_rewind(pa_source *s, size_t nbytes) { } } +/* Called from IO thread context */ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { pa_source_output *o; void *state = NULL; @@ -417,7 +435,9 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) { pa_source_output_assert_ref(o); - pa_source_output_push(o, &vchunk); + + if (!o->thread_info.direct_on_input) + pa_source_output_push(o, &vchunk); } pa_memblock_unref(vchunk.memblock); @@ -425,11 +445,43 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) { pa_source_output_assert_ref(o); - pa_source_output_push(o, chunk); + + if (!o->thread_info.direct_on_input) + pa_source_output_push(o, chunk); } } } +/* Called from IO thread context */ +void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) { + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state)); + pa_source_output_assert_ref(o); + pa_assert(o->thread_info.direct_on_input); + pa_assert(chunk); + + if (s->thread_info.state != PA_SOURCE_RUNNING) + return; + + if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) { + pa_memchunk vchunk = *chunk; + + pa_memblock_ref(vchunk.memblock); + pa_memchunk_make_writable(&vchunk, 0); + + if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume)) + pa_silence_memchunk(&vchunk, &s->sample_spec); + else + pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume); + + pa_source_output_push(o, &vchunk); + + pa_memblock_unref(vchunk.memblock); + } else + pa_source_output_push(o, chunk); +} + +/* Called from main thread */ pa_usec_t pa_source_get_latency(pa_source *s) { pa_usec_t usec; @@ -439,14 +491,14 @@ pa_usec_t pa_source_get_latency(pa_source *s) { if (!PA_SOURCE_IS_OPENED(s->state)) return 0; - if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) - return 0; + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0); return usec; } +/* Called from main thread */ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) { - int changed; + pa_bool_t changed; pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); @@ -459,34 +511,36 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) { s->set_volume = NULL; if (!s->set_volume) - pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, NULL, pa_xfree); + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, volume, 0, NULL); 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) { - pa_cvolume old_volume; - pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); - old_volume = s->volume; + if (s->refresh_volume) { + pa_cvolume old_volume = s->volume; - if (s->get_volume && s->get_volume(s) < 0) - s->get_volume = NULL; + if (s->get_volume && s->get_volume(s) < 0) + s->get_volume = NULL; - if (!s->get_volume && s->refresh_volume) - pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, &s->volume, 0, NULL); + if (!s->get_volume) + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, &s->volume, 0, NULL); - if (!pa_cvolume_equal(&old_volume, &s->volume)) - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + if (!pa_cvolume_equal(&old_volume, &s->volume)) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + } return &s->volume; } +/* Called from main thread */ void pa_source_set_mute(pa_source *s, pa_bool_t mute) { - int changed; + pa_bool_t changed; pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); @@ -504,26 +558,29 @@ void pa_source_set_mute(pa_source *s, pa_bool_t mute) { pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } +/* Called from main thread */ pa_bool_t pa_source_get_mute(pa_source *s) { - pa_bool_t old_muted; pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); - old_muted = s->muted; + if (s->refresh_muted) { + pa_bool_t old_muted = s->muted; - if (s->get_mute && s->get_mute(s) < 0) - s->get_mute = NULL; + if (s->get_mute && s->get_mute(s) < 0) + s->get_mute = NULL; - if (!s->get_mute && s->refresh_muted) - pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, &s->muted, 0, NULL); + if (!s->get_mute) + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, &s->muted, 0, NULL); - if (old_muted != s->muted) - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + if (old_muted != s->muted) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + } return s->muted; } +/* Called from main thread */ void pa_source_set_description(pa_source *s, const char *description) { const char *old; pa_source_assert_ref(s); @@ -547,6 +604,7 @@ void pa_source_set_description(pa_source *s, const char *description) { } } +/* Called from main thread */ unsigned pa_source_linked_by(pa_source *s) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); @@ -554,6 +612,7 @@ unsigned pa_source_linked_by(pa_source *s) { return pa_idxset_size(s->outputs); } +/* Called from main thread */ unsigned pa_source_used_by(pa_source *s) { unsigned ret; @@ -566,17 +625,23 @@ unsigned pa_source_used_by(pa_source *s) { return ret - s->n_corked; } +/* 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); pa_source_assert_ref(s); - pa_assert(s->thread_info.state != PA_SOURCE_UNLINKED); switch ((pa_source_message_t) code) { + case PA_SOURCE_MESSAGE_ADD_OUTPUT: { pa_source_output *o = PA_SOURCE_OUTPUT(userdata); pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o)); + if (o->direct_on_input) { + o->thread_info.direct_on_input = o->direct_on_input; + pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o); + } + pa_assert(!o->thread_info.attached); o->thread_info.attached = TRUE; @@ -606,6 +671,11 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_ pa_assert(o->thread_info.attached); o->thread_info.attached = FALSE; + if (o->thread_info.direct_on_input) { + pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index)); + o->thread_info.direct_on_input = NULL; + } + if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index))) pa_source_output_unref(o); @@ -636,9 +706,7 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_ case PA_SOURCE_MESSAGE_DETACH: - /* We're detaching all our output streams so that the - * asyncmsgq and rtpoll fields can be changed without - * problems */ + /* Detach all streams */ pa_source_detach_within_thread(s); return 0; @@ -652,10 +720,45 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_ pa_usec_t *usec = userdata; *usec = pa_source_get_requested_latency_within_thread(s); + + if (*usec == (pa_usec_t) -1) + *usec = s->thread_info.max_latency; + + return 0; + } + + case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: { + pa_usec_t *r = userdata; + + pa_source_update_latency_range(s, r[0], r[1]); + + return 0; + } + + case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: { + pa_usec_t *r = userdata; + + r[0] = s->thread_info.min_latency; + r[1] = s->thread_info.max_latency; + return 0; } + case PA_SOURCE_MESSAGE_GET_MAX_REWIND: + + *((size_t*) userdata) = s->thread_info.max_rewind; + return 0; + case PA_SOURCE_MESSAGE_GET_LATENCY: + + if (s->monitor_of) { + *((pa_usec_t*) userdata) = 0; + return 0; + } + + /* Implementors need to overwrite this implementation! */ + return -1; + case PA_SOURCE_MESSAGE_MAX: ; } @@ -663,6 +766,7 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_ return -1; } +/* Called from main thread */ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) { uint32_t idx; pa_source *source; @@ -676,20 +780,23 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) { return ret; } +/* Called from main thread */ void pa_source_detach(pa_source *s) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); - pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0); } +/* Called from main thread */ void pa_source_attach(pa_source *s) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); - pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL); + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0); } +/* Called from IO thread */ void pa_source_detach_within_thread(pa_source *s) { pa_source_output *o; void *state = NULL; @@ -702,6 +809,7 @@ void pa_source_detach_within_thread(pa_source *s) { o->detach(o); } +/* Called from IO thread */ void pa_source_attach_within_thread(pa_source *s) { pa_source_output *o; void *state = NULL; @@ -714,6 +822,7 @@ void pa_source_attach_within_thread(pa_source *s) { o->attach(o); } +/* Called from IO thread */ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) { pa_usec_t result = (pa_usec_t) -1; pa_source_output *o; @@ -731,11 +840,11 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) { result = o->thread_info.requested_source_latency; if (result != (pa_usec_t) -1) { - if (s->max_latency > 0 && result > s->max_latency) - result = s->max_latency; + if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency) + result = s->thread_info.max_latency; - if (s->min_latency > 0 && result < s->min_latency) - result = s->min_latency; + if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency) + result = s->thread_info.min_latency; } s->thread_info.requested_latency = result; @@ -744,6 +853,7 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) { return result; } +/* Called from main thread */ pa_usec_t pa_source_get_requested_latency(pa_source *s) { pa_usec_t usec; @@ -753,15 +863,12 @@ pa_usec_t pa_source_get_requested_latency(pa_source *s) { if (!PA_SOURCE_IS_OPENED(s->state)) return 0; - if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) < 0) - return 0; - - if (usec == (pa_usec_t) -1) - usec = s->max_latency; + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); return usec; } +/* Called from IO thread */ void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) { pa_source_output *o; void *state = NULL; @@ -773,17 +880,106 @@ void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) { s->thread_info.max_rewind = max_rewind; - while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) - pa_source_output_update_max_rewind(o, s->thread_info.max_rewind); + if (PA_SOURCE_IS_LINKED(s->thread_info.state)) { + while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + pa_source_output_update_max_rewind(o, s->thread_info.max_rewind); + } } void pa_source_invalidate_requested_latency(pa_source *s) { + pa_source_output *o; + void *state = NULL; pa_source_assert_ref(s); - pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); s->thread_info.requested_latency_valid = FALSE; if (s->update_requested_latency) s->update_requested_latency(s); + + while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + o->update_source_requested_latency(o); + + if (s->monitor_of) + pa_sink_invalidate_requested_latency(s->monitor_of); +} + +void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) { + pa_source_assert_ref(s); + + /* min_latency == 0: no limit + * min_latency == (size_t) -1: default limit + * min_latency anything else: specified limit + * + * Similar for max_latency */ + + if (min_latency == (pa_usec_t) -1) + min_latency = DEFAULT_MIN_LATENCY; + + if (max_latency == (pa_usec_t) -1) + max_latency = min_latency; + + pa_assert(!min_latency || !max_latency || + min_latency <= max_latency); + + if (PA_SINK_IS_LINKED(s->state)) { + pa_usec_t r[2]; + + r[0] = min_latency; + r[1] = max_latency; + + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0); + } else { + s->thread_info.min_latency = min_latency; + s->thread_info.max_latency = max_latency; + + s->thread_info.requested_latency_valid = FALSE; + } +} + +void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) { + pa_source_assert_ref(s); + pa_assert(min_latency); + pa_assert(max_latency); + + if (PA_SOURCE_IS_LINKED(s->state)) { + pa_usec_t r[2] = { 0, 0 }; + + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0); + + *min_latency = r[0]; + *max_latency = r[1]; + } else { + *min_latency = s->thread_info.min_latency; + *max_latency = s->thread_info.max_latency; + } +} + +/* Called from IO thread */ +void pa_source_update_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) { + pa_source_output *o; + void *state = NULL; + + pa_source_assert_ref(s); + + s->thread_info.min_latency = min_latency; + s->thread_info.max_latency = max_latency; + + while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + if (o->update_source_latency_range) + o->update_source_latency_range(o); + + pa_source_invalidate_requested_latency(s); +} + +size_t pa_source_get_max_rewind(pa_source *s) { + size_t r; + pa_source_assert_ref(s); + + if (!PA_SOURCE_IS_LINKED(s->state)) + return s->thread_info.max_rewind; + + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0); + + return r; } diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index f9c9cbf9..f4a17e8d 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -1,8 +1,6 @@ #ifndef foopulsesourcehfoo #define foopulsesourcehfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -42,6 +40,7 @@ typedef struct pa_source pa_source; #include <pulsecore/asyncmsgq.h> #include <pulsecore/msgobject.h> #include <pulsecore/rtpoll.h> +#include <pulsecore/source-output.h> #define PA_MAX_OUTPUTS_PER_SOURCE 32 @@ -84,22 +83,44 @@ struct pa_source { pa_cvolume volume; pa_bool_t muted; - pa_bool_t refresh_volume; - pa_bool_t refresh_muted; + + pa_bool_t refresh_volume:1; + pa_bool_t refresh_muted:1; pa_asyncmsgq *asyncmsgq; pa_rtpoll *rtpoll; pa_memchunk silence; - pa_usec_t min_latency; /* we won't go below this latency setting */ - pa_usec_t max_latency; /* An upper limit for the latencies */ - + /* Called when the main loop requests a state change. Called from + * main loop context. If returns -1 the state change will be + * inhibited */ int (*set_state)(pa_source*source, pa_source_state_t state); /* may be NULL */ - int (*set_volume)(pa_source *s); /* dito */ + + /* Callled when the volume is queried. Called from main loop + * context. If this is NULL a PA_SOURCE_MESSAGE_GET_VOLUME message + * will be sent to the IO thread instead. If refresh_volume is + * FALSE neither this function is called nor a message is sent. */ int (*get_volume)(pa_source *s); /* dito */ - int (*set_mute)(pa_source *s); /* dito */ + + /* Called when the volume shall be changed. Called from main loop + * context. If this is NULL a PA_SOURCE_MESSAGE_SET_VOLUME message + * will be sent to the IO thread instead. */ + int (*set_volume)(pa_source *s); /* dito */ + + /* Called when the mute setting is queried. Called from main loop + * context. If this is NULL a PA_SOURCE_MESSAGE_GET_MUTE message + * will be sent to the IO thread instead. If refresh_mute is + * FALSE neither this function is called nor a message is sent.*/ int (*get_mute)(pa_source *s); /* dito */ + + /* Called when the mute setting shall be changed. Called from main + * loop context. If this is NULL a PA_SOURCE_MESSAGE_SET_MUTE + * message will be sent to the IO thread instead. */ + int (*set_mute)(pa_source *s); /* dito */ + + /* Called when a the requested latency is changed. Called from IO + * thread context. */ void (*update_requested_latency)(pa_source *s); /* dito */ /* Contains copies of the above data so that the real-time worker @@ -108,14 +129,17 @@ struct pa_source { pa_source_state_t state; pa_hashmap *outputs; pa_cvolume soft_volume; - pa_bool_t soft_muted; + pa_bool_t soft_muted:1; - pa_bool_t requested_latency_valid; - size_t requested_latency; + pa_bool_t requested_latency_valid:1; + pa_usec_t requested_latency; /* Then number of bytes this source will be rewound for at - * max */ + * max. (Only used on monitor sources) */ size_t max_rewind; + + pa_usec_t min_latency; /* we won't go below this latency */ + pa_usec_t max_latency; /* An upper limit for the latencies */ } thread_info; void *userdata; @@ -136,6 +160,9 @@ typedef enum pa_source_message { PA_SOURCE_MESSAGE_SET_STATE, PA_SOURCE_MESSAGE_ATTACH, PA_SOURCE_MESSAGE_DETACH, + PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, + PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, + PA_SOURCE_MESSAGE_GET_MAX_REWIND, PA_SOURCE_MESSAGE_MAX } pa_source_message_t; @@ -180,13 +207,19 @@ void pa_source_set_description(pa_source *s, const char *description); void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q); void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p); +void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency); + void pa_source_detach(pa_source *s); void pa_source_attach(pa_source *s); /* May be called by everyone, from main context */ +/* The returned value is supposed to be in the time domain of the sound card! */ pa_usec_t pa_source_get_latency(pa_source *s); pa_usec_t pa_source_get_requested_latency(pa_source *s); +void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency); + +size_t pa_source_get_max_rewind(pa_source *s); int pa_source_update_status(pa_source*s); int pa_source_suspend(pa_source *s, pa_bool_t suspend); @@ -203,7 +236,8 @@ unsigned pa_source_used_by(pa_source *s); /* Number of connected streams that ar /* To be called exclusively by the source driver, from IO context */ -void pa_source_post(pa_source*s, const pa_memchunk *b); +void pa_source_post(pa_source*s, const pa_memchunk *chunk); +void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk); void pa_source_process_rewind(pa_source *s, size_t nbytes); int pa_source_process_msg(pa_msgobject *o, int code, void *userdata, int64_t, pa_memchunk *chunk); @@ -214,6 +248,7 @@ void pa_source_detach_within_thread(pa_source *s); pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s); void pa_source_set_max_rewind(pa_source *s, size_t max_rewind); +void pa_source_update_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency); /* To be called exclusively by source output drivers, from IO context */ diff --git a/src/pulsecore/speexwrap.h b/src/pulsecore/speexwrap.h index df73edf0..617e4afb 100644 --- a/src/pulsecore/speexwrap.h +++ b/src/pulsecore/speexwrap.h @@ -1,8 +1,6 @@ #ifndef foopulsespeexwraphfoo #define foopulsespeexwraphfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/start-child.c b/src/pulsecore/start-child.c index e01011d6..1661383d 100644 --- a/src/pulsecore/start-child.c +++ b/src/pulsecore/start-child.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/start-child.h b/src/pulsecore/start-child.h index 359b5044..0b5ff660 100644 --- a/src/pulsecore/start-child.h +++ b/src/pulsecore/start-child.h @@ -1,8 +1,6 @@ #ifndef foopulsestartchildhfoo #define foopulsestartchildhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/strbuf.c b/src/pulsecore/strbuf.c index 7c576c67..b59b6f49 100644 --- a/src/pulsecore/strbuf.c +++ b/src/pulsecore/strbuf.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/strbuf.h b/src/pulsecore/strbuf.h index d3555a2c..24c876d5 100644 --- a/src/pulsecore/strbuf.h +++ b/src/pulsecore/strbuf.h @@ -1,8 +1,6 @@ #ifndef foostrbufhfoo #define foostrbufhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/strlist.c b/src/pulsecore/strlist.c index ac83f6b1..f587a2f8 100644 --- a/src/pulsecore/strlist.c +++ b/src/pulsecore/strlist.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/strlist.h b/src/pulsecore/strlist.h index 6e6e2d4a..1cb7537a 100644 --- a/src/pulsecore/strlist.h +++ b/src/pulsecore/strlist.h @@ -1,8 +1,6 @@ #ifndef foostrlisthfoo #define foostrlisthfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c index 7616cd16..b0ed59ef 100644 --- a/src/pulsecore/tagstruct.c +++ b/src/pulsecore/tagstruct.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h index 8699e6c8..e7d07054 100644 --- a/src/pulsecore/tagstruct.h +++ b/src/pulsecore/tagstruct.h @@ -1,8 +1,6 @@ #ifndef footagstructhfoo #define footagstructhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/thread-mq.c b/src/pulsecore/thread-mq.c index 7e39c577..34f92a7e 100644 --- a/src/pulsecore/thread-mq.c +++ b/src/pulsecore/thread-mq.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/thread-mq.h b/src/pulsecore/thread-mq.h index 0ae49f8c..3b5e0e78 100644 --- a/src/pulsecore/thread-mq.h +++ b/src/pulsecore/thread-mq.h @@ -1,8 +1,6 @@ #ifndef foopulsethreadmqhfoo #define foopulsethreadmqhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index 7f43f43e..20ed16d9 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/thread-win32.c b/src/pulsecore/thread-win32.c index cad1420a..c40d3342 100644 --- a/src/pulsecore/thread-win32.c +++ b/src/pulsecore/thread-win32.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h index 54ef320e..f3aca13e 100644 --- a/src/pulsecore/thread.h +++ b/src/pulsecore/thread.h @@ -1,8 +1,6 @@ #ifndef foopulsethreadhfoo #define foopulsethreadhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c index 9b4be29f..fe5a4f18 100644 --- a/src/pulsecore/time-smoother.c +++ b/src/pulsecore/time-smoother.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -451,3 +449,11 @@ pa_usec_t pa_smoother_translate(pa_smoother *s, pa_usec_t x, pa_usec_t y_delay) return (pa_usec_t) ((double) y_delay / nde); } + +void pa_smoother_reset(pa_smoother *s) { + pa_assert(s); + + s->n_history = 0; + s->abc_valid = FALSE; + +} diff --git a/src/pulsecore/time-smoother.h b/src/pulsecore/time-smoother.h index b301b48c..2051e640 100644 --- a/src/pulsecore/time-smoother.h +++ b/src/pulsecore/time-smoother.h @@ -1,8 +1,6 @@ #ifndef foopulsetimesmootherhfoo #define foopulsetimesmootherhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -46,4 +44,6 @@ void pa_smoother_set_time_offset(pa_smoother *s, pa_usec_t x_offset); void pa_smoother_pause(pa_smoother *s, pa_usec_t x); void pa_smoother_resume(pa_smoother *s, pa_usec_t x); +void pa_smoother_reset(pa_smoother *s); + #endif diff --git a/src/pulsecore/tokenizer.c b/src/pulsecore/tokenizer.c index cf5da648..d1e0836b 100644 --- a/src/pulsecore/tokenizer.c +++ b/src/pulsecore/tokenizer.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/tokenizer.h b/src/pulsecore/tokenizer.h index 68a8db49..d51cd73e 100644 --- a/src/pulsecore/tokenizer.h +++ b/src/pulsecore/tokenizer.h @@ -1,8 +1,6 @@ #ifndef footokenizerhfoo #define footokenizerhfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/x11prop.c b/src/pulsecore/x11prop.c index a740e39b..9e75f63a 100644 --- a/src/pulsecore/x11prop.c +++ b/src/pulsecore/x11prop.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/x11prop.h b/src/pulsecore/x11prop.h index 388c5a34..c5998d3e 100644 --- a/src/pulsecore/x11prop.h +++ b/src/pulsecore/x11prop.h @@ -1,8 +1,6 @@ #ifndef foox11prophfoo #define foox11prophfoo -/* $Id$ */ - /*** This file is part of PulseAudio. diff --git a/src/pulsecore/x11wrap.c b/src/pulsecore/x11wrap.c index 800a9458..00b6a157 100644 --- a/src/pulsecore/x11wrap.c +++ b/src/pulsecore/x11wrap.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -63,7 +61,8 @@ struct pa_x11_wrapper { struct pa_x11_client { PA_LLIST_FIELDS(pa_x11_client); pa_x11_wrapper *wrapper; - int (*callback)(pa_x11_wrapper *w, XEvent *e, void *userdata); + pa_x11_event_cb_t event_cb; + pa_x11_kill_cb_t kill_cb; void *userdata; }; @@ -72,17 +71,23 @@ static void work(pa_x11_wrapper *w) { pa_assert(w); pa_assert(PA_REFCNT_VALUE(w) >= 1); + pa_x11_wrapper_ref(w); + while (XPending(w->display)) { - pa_x11_client *c; + pa_x11_client *c, *n; XEvent e; XNextEvent(w->display, &e); - for (c = w->clients; c; c = c->next) { - pa_assert(c->callback); - if (c->callback(w, &e, c->userdata) != 0) - break; + for (c = w->clients; c; c = n) { + n = c->next; + + if (c->event_cb) + if (c->event_cb(w, &e, c->userdata) != 0) + break; } } + + pa_x11_wrapper_unref(w); } /* IO notification event for the X11 display connection */ @@ -251,7 +256,24 @@ Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) { return w->display; } -pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) { +void pa_x11_wrapper_kill(pa_x11_wrapper *w) { + pa_x11_client *c, *n; + + pa_assert(w); + + pa_x11_wrapper_ref(w); + + for (c = w->clients; c; c = n) { + n = c->next; + + if (c->kill_cb) + c->kill_cb(w, c->userdata); + } + + pa_x11_wrapper_unref(w); +} + +pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, pa_x11_event_cb_t event_cb, pa_x11_kill_cb_t kill_cb, void *userdata) { pa_x11_client *c; pa_assert(w); @@ -259,7 +281,8 @@ pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, c = pa_xnew(pa_x11_client, 1); c->wrapper = w; - c->callback = cb; + c->event_cb = event_cb; + c->kill_cb = kill_cb; c->userdata = userdata; PA_LLIST_PREPEND(pa_x11_client, w->clients, c); diff --git a/src/pulsecore/x11wrap.h b/src/pulsecore/x11wrap.h index 9bed2fce..badc3a1f 100644 --- a/src/pulsecore/x11wrap.h +++ b/src/pulsecore/x11wrap.h @@ -1,8 +1,6 @@ #ifndef foox11wraphfoo #define foox11wraphfoo -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -30,6 +28,11 @@ typedef struct pa_x11_wrapper pa_x11_wrapper; +typedef struct pa_x11_client pa_x11_client; + +typedef int (*pa_x11_event_cb_t)(pa_x11_wrapper *w, XEvent *e, void *userdata); +typedef void (*pa_x11_kill_cb_t)(pa_x11_wrapper *w, void *userdata); + /* Return the X11 wrapper for this core. In case no wrapper was existant before, allocate a new one */ pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name); @@ -43,10 +46,11 @@ void pa_x11_wrapper_unref(pa_x11_wrapper* w); /* Return the X11 display object for this connection */ Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w); -typedef struct pa_x11_client pa_x11_client; +/* Kill the connection to the X11 display */ +void pa_x11_wrapper_kill(pa_x11_wrapper *w); /* Register an X11 client, that is called for each X11 event */ -pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata); +pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, pa_x11_event_cb_t event_cb, pa_x11_kill_cb_t kill_cb, void *userdata); /* Free an X11 client object */ void pa_x11_client_free(pa_x11_client *c); |