diff options
Diffstat (limited to 'src/pulsecore')
-rw-r--r-- | src/pulsecore/cli-text.c | 8 | ||||
-rw-r--r-- | src/pulsecore/core-util.c | 47 | ||||
-rw-r--r-- | src/pulsecore/core-util.h | 4 | ||||
-rw-r--r-- | src/pulsecore/envelope.c | 8 | ||||
-rw-r--r-- | src/pulsecore/idxset.c | 42 | ||||
-rw-r--r-- | src/pulsecore/ltdl-helper.c | 6 | ||||
-rw-r--r-- | src/pulsecore/macro.h | 16 | ||||
-rw-r--r-- | src/pulsecore/modargs.c | 179 | ||||
-rw-r--r-- | src/pulsecore/namereg.c | 2 | ||||
-rw-r--r-- | src/pulsecore/play-memblockq.c | 4 | ||||
-rw-r--r-- | src/pulsecore/proplist-util.c | 63 | ||||
-rw-r--r-- | src/pulsecore/protocol-esound.c | 4 | ||||
-rw-r--r-- | src/pulsecore/protocol-native.c | 51 | ||||
-rw-r--r-- | src/pulsecore/protocol-simple.c | 4 | ||||
-rw-r--r-- | src/pulsecore/resampler.c | 12 | ||||
-rw-r--r-- | src/pulsecore/sink-input.c | 179 | ||||
-rw-r--r-- | src/pulsecore/sink-input.h | 15 | ||||
-rw-r--r-- | src/pulsecore/sink.c | 80 | ||||
-rw-r--r-- | src/pulsecore/sound-file-stream.c | 4 | ||||
-rw-r--r-- | src/pulsecore/source-output.c | 88 | ||||
-rw-r--r-- | src/pulsecore/source-output.h | 6 | ||||
-rw-r--r-- | src/pulsecore/source.c | 33 |
22 files changed, 529 insertions, 326 deletions
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index 57129d0c..8ca8f2d9 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -421,7 +421,7 @@ char *pa_source_output_list_to_string(pa_core *c) { s, " index: %u\n" "\tdriver: <%s>\n" - "\tflags: %s%s%s%s%s%s%s%s\n" + "\tflags: %s%s%s%s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsource: %u <%s>\n" "\tcurrent latency: %0.2f ms\n" @@ -439,6 +439,8 @@ char *pa_source_output_list_to_string(pa_core *c) { o->flags & PA_SOURCE_OUTPUT_FIX_FORMAT ? "FIX_FORMAT " : "", o->flags & PA_SOURCE_OUTPUT_FIX_RATE ? "FIX_RATE " : "", o->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "", + o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND ? "DONT_INHIBIT_AUTO_SUSPEND " : "", + o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND ? "FAIL_ON_SUSPEND " : "", state_table[pa_source_output_get_state(o)], o->source->index, o->source->name, (double) pa_source_output_get_latency(o, NULL) / PA_USEC_PER_MSEC, @@ -498,7 +500,7 @@ char *pa_sink_input_list_to_string(pa_core *c) { s, " index: %u\n" "\tdriver: <%s>\n" - "\tflags: %s%s%s%s%s%s%s%s\n" + "\tflags: %s%s%s%s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsink: %u <%s>\n" "\tvolume: %s\n" @@ -520,6 +522,8 @@ char *pa_sink_input_list_to_string(pa_core *c) { i->flags & PA_SINK_INPUT_FIX_FORMAT ? "FIX_FORMAT " : "", i->flags & PA_SINK_INPUT_FIX_RATE ? "FIX_RATE " : "", i->flags & PA_SINK_INPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "", + i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND ? "DONT_INHIBIT_AUTO_SUSPEND " : "", + i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND ? "FAIL_ON_SUSPEND " : "", state_table[pa_sink_input_get_state(i)], i->sink->index, i->sink->name, pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index e65b1796..b7ebdeb7 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -97,6 +97,7 @@ #include <pulsecore/log.h> #include <pulsecore/macro.h> #include <pulsecore/thread.h> +#include <pulsecore/strbuf.h> #include "core-util.h" @@ -2553,3 +2554,49 @@ unsigned pa_ncpus(void) { return ncpus <= 0 ? 1 : (unsigned) ncpus; } + +char *pa_replace(const char*s, const char*a, const char *b) { + pa_strbuf *sb; + size_t an; + + pa_assert(s); + pa_assert(a); + pa_assert(b); + + an = strlen(a); + sb = pa_strbuf_new(); + + for (;;) { + const char *p; + + if (!(p = strstr(s, a))) + break; + + pa_strbuf_putsn(sb, s, p-s); + pa_strbuf_puts(sb, b); + s = p + an; + } + + pa_strbuf_puts(sb, s); + + return pa_strbuf_tostring_free(sb); +} + +char *pa_unescape(char *p) { + char *s, *d; + pa_bool_t escaped = FALSE; + + for (s = p, d = p; *s; s++) { + if (!escaped && *s == '\\') { + escaped = TRUE; + continue; + } + + *(d++) = *s; + escaped = FALSE; + } + + *d = 0; + + return p; +} diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 18901f47..442815f1 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -215,4 +215,8 @@ void pa_reduce(unsigned *num, unsigned *den); unsigned pa_ncpus(void); +char *pa_replace(const char*s, const char*a, const char *b); + +char *pa_unescape(char *p); + #endif diff --git a/src/pulsecore/envelope.c b/src/pulsecore/envelope.c index f872d347..fd6a9487 100644 --- a/src/pulsecore/envelope.c +++ b/src/pulsecore/envelope.c @@ -599,7 +599,6 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { switch (e->sample_spec.format) { - case PA_SAMPLE_U8: { uint8_t *t; @@ -745,6 +744,13 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { break; } + case PA_SAMPLE_S24LE: + case PA_SAMPLE_S24BE: + case PA_SAMPLE_S24_32LE: + case PA_SAMPLE_S24_32BE: + /* FIXME */ + pa_assert_not_reached(); + case PA_SAMPLE_MAX: case PA_SAMPLE_INVALID: pa_assert_not_reached(); diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index 24a28db7..352ac977 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -386,8 +386,11 @@ void* pa_idxset_steal_first(pa_idxset *s, uint32_t *idx) { void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { pa_assert(s); - if (!s->iterate_list_head) + if (!s->iterate_list_head) { + if (idx) + *idx = PA_IDXSET_INVALID; return NULL; + } if (idx) *idx = s->iterate_list_head->idx; @@ -402,20 +405,41 @@ void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { pa_assert(s); pa_assert(idx); + if (*idx == PA_IDXSET_INVALID) + return NULL; + hash = *idx % NBUCKETS; - if (!(e = index_scan(s, hash, *idx))) - return NULL; + if ((e = index_scan(s, hash, *idx))) { + + e = e->iterate_next; + + if (e) { + *idx = e->idx; + return e->data; + } else { + *idx = PA_IDXSET_INVALID; + return NULL; + } + + } else { + + /* If the entry passed doesn't exist anymore we try to find + * the next following */ + + for ((*idx)++; *idx < s->current_index; (*idx)++) { + + hash = *idx % NBUCKETS; + + if ((e = index_scan(s, hash, *idx))) { + *idx = e->idx; + return e->data; + } + } - if (!e->iterate_next) { *idx = PA_IDXSET_INVALID; return NULL; } - - e = e->iterate_next; - - *idx = e->idx; - return e->data; } unsigned pa_idxset_size(pa_idxset*s) { diff --git a/src/pulsecore/ltdl-helper.c b/src/pulsecore/ltdl-helper.c index 0d4c22f8..ed0b63af 100644 --- a/src/pulsecore/ltdl-helper.c +++ b/src/pulsecore/ltdl-helper.c @@ -42,7 +42,9 @@ pa_void_func_t pa_load_sym(lt_dlhandle handle, const char *module, const char *s pa_assert(handle); pa_assert(symbol); - if ((f = ((pa_void_func_t) (size_t) lt_dlsym(handle, symbol)))) + *(void**) &f = lt_dlsym(handle, symbol); + + if (f) return f; if (!module) @@ -57,7 +59,7 @@ pa_void_func_t pa_load_sym(lt_dlhandle handle, const char *module, const char *s if (!isalnum(*c)) *c = '_'; - f = (pa_void_func_t) (size_t) lt_dlsym(handle, sn); + *(void**) &f = lt_dlsym(handle, sn); pa_xfree(sn); return f; diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index f9ce949a..59460012 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -187,17 +187,17 @@ typedef int pa_bool_t; abort(); \ } while (FALSE) -#define PA_PTR_TO_UINT(p) ((unsigned int) (unsigned long) (p)) -#define PA_UINT_TO_PTR(u) ((void*) (unsigned long) (u)) +#define PA_PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) +#define PA_UINT_TO_PTR(u) ((void*) ((uintptr_t) (u))) -#define PA_PTR_TO_UINT32(p) ((uint32_t) PA_PTR_TO_UINT(p)) -#define PA_UINT32_TO_PTR(u) PA_UINT_TO_PTR((uint32_t) u) +#define PA_PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p))) +#define PA_UINT32_TO_PTR(u) ((void*) ((uintptr_t) (u))) -#define PA_PTR_TO_INT(p) ((int) PA_PTR_TO_UINT(p)) -#define PA_INT_TO_PTR(u) PA_UINT_TO_PTR((int) u) +#define PA_PTR_TO_INT(p) ((int) ((intptr_t) (p))) +#define PA_INT_TO_PTR(u) ((void*) ((intptr_t) (u))) -#define PA_PTR_TO_INT32(p) ((int32_t) PA_PTR_TO_UINT(p)) -#define PA_INT32_TO_PTR(u) PA_UINT_TO_PTR((int32_t) u) +#define PA_PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p))) +#define PA_INT32_TO_PTR(u) ((void*) ((intptr_t) (u))) #ifdef OS_IS_WIN32 #define PA_PATH_SEP "\\" diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c index 9e60125e..866e6e0c 100644 --- a/src/pulsecore/modargs.c +++ b/src/pulsecore/modargs.c @@ -79,106 +79,111 @@ static int add_key_value(pa_hashmap *map, char *key, char *value, const char* co } pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) { - pa_hashmap *map = NULL; + enum { + WHITESPACE, + KEY, + VALUE_START, + VALUE_SIMPLE, + VALUE_DOUBLE_QUOTES, + VALUE_TICKS + } state; + + const char *p, *key = NULL, *value = NULL; + size_t key_len = 0, value_len = 0; + pa_hashmap *map; 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; - - const char *p, *key, *value; - size_t key_len = 0, value_len = 0; - - key = value = NULL; - state = WHITESPACE; - for (p = args; *p; p++) { - switch (state) { - case WHITESPACE: - if (*p == '=') + if (!args) + return (pa_modargs*) map; + + state = WHITESPACE; + + for (p = args; *p; p++) { + switch (state) { + + case WHITESPACE: + if (*p == '=') + goto fail; + else if (!isspace(*p)) { + key = p; + state = KEY; + key_len = 1; + } + break; + + case KEY: + if (*p == '=') + state = VALUE_START; + else if (isspace(*p)) + goto fail; + else + key_len++; + break; + + case VALUE_START: + if (*p == '\'') { + state = VALUE_TICKS; + value = p+1; + value_len = 0; + } else if (*p == '"') { + state = VALUE_DOUBLE_QUOTES; + value = p+1; + value_len = 0; + } else if (isspace(*p)) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) goto fail; - else if (!isspace(*p)) { - key = p; - state = KEY; - key_len = 1; - } - break; - case KEY: - if (*p == '=') - state = VALUE_START; - else if (isspace(*p)) + state = WHITESPACE; + } else { + state = VALUE_SIMPLE; + value = p; + value_len = 1; + } + break; + + case VALUE_SIMPLE: + if (isspace(*p)) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) goto fail; - else - key_len++; - break; - case VALUE_START: - if (*p == '\'') { - state = VALUE_TICKS; - value = p+1; - value_len = 0; - } else if (*p == '"') { - state = VALUE_DOUBLE_QUOTES; - value = p+1; - value_len = 0; - } else if (isspace(*p)) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else { - state = VALUE_SIMPLE; - value = p; - value_len = 1; - } - break; - case VALUE_SIMPLE: - if (isspace(*p)) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - case VALUE_DOUBLE_QUOTES: - if (*p == '"') { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - case VALUE_TICKS: - if (*p == '\'') { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) - goto fail; - state = WHITESPACE; - } else - value_len++; - break; - } + state = WHITESPACE; + } else + value_len++; + break; + + case VALUE_DOUBLE_QUOTES: + if (*p == '"') { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; + + case VALUE_TICKS: + if (*p == '\'') { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrndup(value, value_len), valid_keys) < 0) + goto fail; + state = WHITESPACE; + } else + value_len++; + break; } + } - if (state == VALUE_START) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) - goto fail; - } else if (state == VALUE_SIMPLE) { - if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0) - goto fail; - } else if (state != WHITESPACE) + if (state == VALUE_START) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(""), valid_keys) < 0) goto fail; - } + } else if (state == VALUE_SIMPLE) { + if (add_key_value(map, pa_xstrndup(key, key_len), pa_xstrdup(value), valid_keys) < 0) + goto fail; + } else if (state != WHITESPACE) + goto fail; return (pa_modargs*) map; fail: - if (map) - pa_modargs_free((pa_modargs*) map); + pa_modargs_free((pa_modargs*) map); return NULL; } diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index ac456ac7..86bcef74 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -194,7 +194,7 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type) { } - if (*name == '@' || !name || !pa_namereg_is_valid_name(name)) + if (!name || *name == '@' || !pa_namereg_is_valid_name(name)) return NULL; if ((e = pa_hashmap_get(c->namereg, name))) diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c index eac21de5..44aa6bf0 100644 --- a/src/pulsecore/play-memblockq.c +++ b/src/pulsecore/play-memblockq.c @@ -197,10 +197,10 @@ pa_sink_input* pa_memblockq_sink_input_new( data.driver = __FILE__; pa_sink_input_new_data_set_sample_spec(&data, ss); pa_sink_input_new_data_set_channel_map(&data, map); - pa_sink_input_new_data_set_virtual_volume(&data, volume); + pa_sink_input_new_data_set_volume(&data, volume); pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p); - u->sink_input = pa_sink_input_new(sink->core, &data, 0); + pa_sink_input_new(&u->sink_input, sink->core, &data, 0); pa_sink_input_new_data_done(&data); if (!u->sink_input) diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c index 35c9985a..522c7afe 100644 --- a/src/pulsecore/proplist-util.c +++ b/src/pulsecore/proplist-util.c @@ -25,6 +25,7 @@ #include <string.h> #include <locale.h> +#include <dlfcn.h> #include <pulse/proplist.h> #include <pulse/utf8.h> @@ -36,11 +37,11 @@ #include "proplist-util.h" void pa_init_proplist(pa_proplist *p) { - int a, b; #if !HAVE_DECL_ENVIRON extern char **environ; #endif char **e; + const char *pp; pa_assert(p); @@ -75,6 +76,15 @@ void pa_init_proplist(pa_proplist *p) { } } + if ((pp = getenv("PULSE_PROP"))) { + pa_proplist *t; + + if ((t = pa_proplist_from_string(pp))) { + pa_proplist_update(p, PA_UPDATE_MERGE, t); + pa_proplist_free(t); + } + } + if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_ID)) { char t[32]; pa_snprintf(t, sizeof(t), "%lu", (unsigned long) getpid()); @@ -99,22 +109,36 @@ void pa_init_proplist(pa_proplist *p) { } } - a = pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_BINARY); - b = pa_proplist_contains(p, PA_PROP_APPLICATION_NAME); - - if (!a || !b) { + if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_BINARY)) { char t[PATH_MAX]; if (pa_get_binary_name(t, sizeof(t))) { char *c = pa_utf8_filter(t); + pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_BINARY, c); + pa_xfree(c); + } + } - if (!a) - pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_BINARY, c); - if (!b) - pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, c); +#ifdef RTLD_NOLOAD + if (!pa_proplist_contains(p, PA_PROP_APPLICATION_NAME)) { + void *dl; - pa_xfree(c); + if ((dl = dlopen("libglib-2.0", RTLD_NOLOAD))) { + const char *(*_g_get_application_name)(void); + + if ((*(void**) &_g_get_application_name = dlsym(dl, "g_get_application_name"))) + pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, _g_get_application_name()); + + dlclose(dl); } } +#endif + + if (!pa_proplist_contains(p, PA_PROP_APPLICATION_NAME)) { + const char *t; + + if ((t = pa_proplist_gets(p, PA_PROP_APPLICATION_PROCESS_BINARY))) + pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, t); + } if (!pa_proplist_contains(p, PA_PROP_APPLICATION_LANGUAGE)) { const char *l; @@ -122,4 +146,23 @@ void pa_init_proplist(pa_proplist *p) { if ((l = setlocale(LC_MESSAGES, NULL))) pa_proplist_sets(p, PA_PROP_APPLICATION_LANGUAGE, l); } + + if (!pa_proplist_contains(p, PA_PROP_WINDOW_X11_DISPLAY)) { + const char *t; + + if ((t = getenv("DISPLAY"))) { + char *c = pa_utf8_filter(t); + pa_proplist_sets(p, PA_PROP_WINDOW_X11_DISPLAY, c); + pa_xfree(c); + } + } + + if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_MACHINE_ID)) { + char *m; + + if ((m = pa_machine_id())) { + pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_MACHINE_ID, m); + pa_xfree(m); + } + } } diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 1311e678..e1643cbb 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -424,7 +424,7 @@ static int esd_proto_stream_play(connection *c, esd_proto_t request, const void sdata.sink = sink; pa_sink_input_new_data_set_sample_spec(&sdata, &ss); - c->sink_input = pa_sink_input_new(c->protocol->core, &sdata, 0); + pa_sink_input_new(&c->sink_input, c->protocol->core, &sdata, 0); pa_sink_input_new_data_done(&sdata); CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); @@ -526,7 +526,7 @@ static int esd_proto_stream_record(connection *c, esd_proto_t request, const voi sdata.source = source; pa_source_output_new_data_set_sample_spec(&sdata, &ss); - c->source_output = pa_source_output_new(c->protocol->core, &sdata, 0); + pa_source_output_new(&c->source_output, c->protocol->core, &sdata, 0); pa_source_output_new_data_done(&sdata); CHECK_VALIDITY(c->source_output, "Failed to create source output."); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index c9621652..39c834d8 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -591,10 +591,11 @@ static record_stream* record_stream_new( pa_proplist *p, pa_bool_t adjust_latency, pa_sink_input *direct_on_input, - pa_bool_t early_requests) { + pa_bool_t early_requests, + int *ret) { record_stream *s; - pa_source_output *source_output; + pa_source_output *source_output = NULL; size_t base; pa_source_output_new_data data; @@ -602,6 +603,7 @@ static record_stream* record_stream_new( pa_assert(ss); pa_assert(maxlength); pa_assert(p); + pa_assert(ret); pa_source_output_new_data_init(&data); @@ -616,7 +618,7 @@ static record_stream* record_stream_new( if (peak_detect) data.resample_method = PA_RESAMPLER_PEAKS; - source_output = pa_source_output_new(c->protocol->core, &data, flags); + *ret = -pa_source_output_new(&source_output, c->protocol->core, &data, flags); pa_source_output_new_data_done(&data); @@ -965,10 +967,11 @@ static playback_stream* playback_stream_new( pa_sink_input_flags_t flags, pa_proplist *p, pa_bool_t adjust_latency, - pa_bool_t early_requests) { + pa_bool_t early_requests, + int *ret) { playback_stream *s, *ssync; - pa_sink_input *sink_input; + pa_sink_input *sink_input = NULL; pa_memchunk silence; uint32_t idx; int64_t start_index; @@ -982,6 +985,7 @@ static playback_stream* playback_stream_new( pa_assert(minreq); pa_assert(missing); pa_assert(p); + pa_assert(ret); /* Find syncid group */ for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) { @@ -998,8 +1002,10 @@ static playback_stream* playback_stream_new( if (!sink) sink = ssync->sink_input->sink; - else if (sink != ssync->sink_input->sink) + else if (sink != ssync->sink_input->sink) { + *ret = PA_ERR_INVALID; return NULL; + } } pa_sink_input_new_data_init(&data); @@ -1012,12 +1018,12 @@ static playback_stream* playback_stream_new( pa_sink_input_new_data_set_sample_spec(&data, ss); pa_sink_input_new_data_set_channel_map(&data, map); if (volume) - pa_sink_input_new_data_set_virtual_volume(&data, volume); + pa_sink_input_new_data_set_volume(&data, volume); if (muted_set) pa_sink_input_new_data_set_muted(&data, muted); data.sync_base = ssync ? ssync->sink_input : NULL; - sink_input = pa_sink_input_new(c->protocol->core, &data, flags); + *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data, flags); pa_sink_input_new_data_done(&data); @@ -1691,11 +1697,12 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u adjust_latency = FALSE, early_requests = FALSE, dont_inhibit_auto_suspend = FALSE, - muted_set = FALSE; - + muted_set = FALSE, + fail_on_suspend = FALSE; pa_sink_input_flags_t flags = 0; pa_proplist *p; pa_bool_t volume_set = TRUE; + int ret = PA_ERR_INVALID; pa_native_connection_assert_ref(c); pa_assert(t); @@ -1775,7 +1782,8 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u if (c->version >= 15) { if (pa_tagstruct_get_boolean(t, &muted_set) < 0 || - pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0) { + pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 || + pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) { protocol_error(c); pa_proplist_free(p); return; @@ -1814,16 +1822,17 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) | (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) | (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) | - (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0); + (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) | + (fail_on_suspend ? PA_SINK_INPUT_FAIL_ON_SUSPEND : 0); /* Only since protocol version 15 there's a seperate muted_set * flag. For older versions we synthesize it here */ muted_set = muted_set || muted; - s = playback_stream_new(c, sink, &ss, &map, &maxlength, &tlength, &prebuf, &minreq, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests); + s = playback_stream_new(c, sink, &ss, &map, &maxlength, &tlength, &prebuf, &minreq, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, &ret); pa_proplist_free(p); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, s, tag, ret); reply = reply_new(tag); pa_tagstruct_putu32(reply, s->index); @@ -1942,11 +1951,13 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin adjust_latency = FALSE, peak_detect = FALSE, early_requests = FALSE, - dont_inhibit_auto_suspend = FALSE; + dont_inhibit_auto_suspend = FALSE, + fail_on_suspend = 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; + int ret = PA_ERR_INVALID; pa_native_connection_assert_ref(c); pa_assert(t); @@ -2016,7 +2027,8 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin if (c->version >= 15) { - if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0) { + if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 || + pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) { protocol_error(c); pa_proplist_free(p); return; @@ -2064,12 +2076,13 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) | (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) | (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) | - (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0); + (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) | + (fail_on_suspend ? PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND : 0); - s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input, early_requests); + s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input, early_requests, &ret); pa_proplist_free(p); - CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, s, tag, ret); reply = reply_new(tag); pa_tagstruct_putu32(reply, s->index); diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index dd8002a3..e149c40d 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -539,7 +539,7 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist); pa_sink_input_new_data_set_sample_spec(&data, &o->sample_spec); - c->sink_input = pa_sink_input_new(p->core, &data, 0); + pa_sink_input_new(&c->sink_input, p->core, &data, 0); pa_sink_input_new_data_done(&data); if (!c->sink_input) { @@ -591,7 +591,7 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist); pa_source_output_new_data_set_sample_spec(&data, &o->sample_spec); - c->source_output = pa_source_output_new(p->core, &data, 0); + pa_source_output_new(&c->source_output, p->core, &data, 0); pa_source_output_new_data_done(&data); if (!c->source_output) { diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index be390db7..78ad5530 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -156,16 +156,6 @@ static int (* const init_table[])(pa_resampler*r) = { [PA_RESAMPLER_PEAKS] = peaks_init, }; -static inline size_t sample_size(pa_sample_format_t f) { - pa_sample_spec ss = { - .format = f, - .rate = 0, - .channels = 1 - }; - - return pa_sample_size(&ss); -} - pa_resampler* pa_resampler_new( pa_mempool *pool, const pa_sample_spec *a, @@ -275,7 +265,7 @@ pa_resampler* pa_resampler_new( pa_log_info("Using %s as working format.", pa_sample_format_to_string(r->work_format)); - r->w_sz = sample_size(r->work_format); + r->w_sz = pa_sample_size_of_format(r->work_format); if (r->i_ss.format == r->work_format) r->to_work_format_func = NULL; diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index d4d11194..df42cae8 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -72,18 +72,11 @@ void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const data->channel_map = *map; } -void pa_sink_input_new_data_set_soft_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) { +void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) { pa_assert(data); - if ((data->soft_volume_is_set = !!volume)) - data->soft_volume = *volume; -} - -void pa_sink_input_new_data_set_virtual_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) { - pa_assert(data); - - if ((data->virtual_volume_is_set = !!volume)) - data->virtual_volume = *volume; + if ((data->volume_is_set = !!volume)) + data->volume = *volume; } void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute) { @@ -120,7 +113,8 @@ static void reset_callbacks(pa_sink_input *i) { } /* Called from main context */ -pa_sink_input* pa_sink_input_new( +int pa_sink_input_new( + pa_sink_input **_i, pa_core *core, pa_sink_input_new_data *data, pa_sink_input_flags_t flags) { @@ -129,28 +123,34 @@ pa_sink_input* pa_sink_input_new( pa_resampler *resampler = NULL; char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_channel_map original_cm; + int r; + pa_assert(_i); pa_assert(core); pa_assert(data); - if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data) < 0) - return NULL; + if (data->client) + pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist); - pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver)); + if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data)) < 0) + return r; + + pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID); if (!data->sink) { data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK); data->save_sink = FALSE; } - pa_return_null_if_fail(data->sink); - pa_return_null_if_fail(pa_sink_get_state(data->sink) != PA_SINK_UNLINKED); - pa_return_null_if_fail(!data->sync_base || (data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED)); + pa_return_val_if_fail(data->sink, -PA_ERR_NOENTITY); + pa_return_val_if_fail(PA_SINK_IS_LINKED(pa_sink_get_state(data->sink)), -PA_ERR_BADSTATE); + pa_return_val_if_fail(!data->sync_base || (data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED), -PA_ERR_INVALID); + pa_return_val_if_fail(!(flags & PA_SINK_INPUT_FAIL_ON_SUSPEND) || pa_sink_get_state(data->sink) != PA_SINK_SUSPENDED, -PA_ERR_BADSTATE); if (!data->sample_spec_is_set) data->sample_spec = data->sink->sample_spec; - pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec)); + pa_return_val_if_fail(pa_sample_spec_valid(&data->sample_spec), -PA_ERR_INVALID); if (!data->channel_map_is_set) { if (pa_channel_map_compatible(&data->sink->channel_map, &data->sample_spec)) @@ -159,38 +159,23 @@ pa_sink_input* pa_sink_input_new( pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); } - pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); - pa_return_null_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec)); + pa_return_val_if_fail(pa_channel_map_valid(&data->channel_map), -PA_ERR_INVALID); + pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID); - if (!data->virtual_volume_is_set) { + if (!data->volume_is_set) { if (data->sink->flags & PA_SINK_FLAT_VOLUME) { - data->virtual_volume = data->sink->virtual_volume; - pa_cvolume_remap(&data->virtual_volume, &data->sink->channel_map, &data->channel_map); + data->volume = *pa_sink_get_volume(data->sink, FALSE); + pa_cvolume_remap(&data->volume, &data->sink->channel_map, &data->channel_map); } else - pa_cvolume_reset(&data->virtual_volume, data->sample_spec.channels); + pa_cvolume_reset(&data->volume, data->sample_spec.channels); data->save_volume = FALSE; - } else if (!data->virtual_volume_is_absolute) { - - /* When the 'absolute' bool is set then we'll treat the volume - * as relative to the sink volume even in flat volume mode */ - if (data->sink->flags & PA_SINK_FLAT_VOLUME) { - pa_cvolume t = data->sink->virtual_volume; - pa_cvolume_remap(&t, &data->sink->channel_map, &data->channel_map); - pa_sw_cvolume_multiply(&data->virtual_volume, &data->virtual_volume, &t); - } } - pa_return_null_if_fail(pa_cvolume_valid(&data->virtual_volume)); - pa_return_null_if_fail(pa_cvolume_compatible(&data->virtual_volume, &data->sample_spec)); - - if (!data->soft_volume_is_set) - data->soft_volume = data->virtual_volume; - - pa_return_null_if_fail(pa_cvolume_valid(&data->soft_volume)); - pa_return_null_if_fail(pa_cvolume_compatible(&data->soft_volume, &data->sample_spec)); + pa_return_val_if_fail(pa_cvolume_valid(&data->volume), -PA_ERR_INVALID); + pa_return_val_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec), -PA_ERR_INVALID); if (!data->muted_is_set) data->muted = FALSE; @@ -212,23 +197,19 @@ pa_sink_input* pa_sink_input_new( pa_assert(pa_channel_map_valid(&data->channel_map)); /* Due to the fixing of the sample spec the volume might not match anymore */ - pa_cvolume_remap(&data->soft_volume, &original_cm, &data->channel_map); - pa_cvolume_remap(&data->virtual_volume, &original_cm, &data->channel_map); + pa_cvolume_remap(&data->volume, &original_cm, &data->channel_map); if (data->resample_method == PA_RESAMPLER_INVALID) data->resample_method = core->resample_method; - pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX); - - if (data->client) - pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist); + pa_return_val_if_fail(data->resample_method < PA_RESAMPLER_MAX, -PA_ERR_INVALID); - if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data) < 0) - return NULL; + if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0) + return r; if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) { pa_log_warn("Failed to create sink input: too many inputs per sink."); - return NULL; + return -PA_ERR_TOOLARGE; } if ((flags & PA_SINK_INPUT_VARIABLE_RATE) || @@ -245,7 +226,7 @@ pa_sink_input* pa_sink_input_new( (core->disable_remixing || (flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) | (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) { pa_log_warn("Unsupported resampling operation."); - return NULL; + return -PA_ERR_NOTSUPPORTED; } } @@ -267,8 +248,18 @@ pa_sink_input* pa_sink_input_new( i->sample_spec = data->sample_spec; i->channel_map = data->channel_map; - i->virtual_volume = data->virtual_volume; - i->soft_volume = data->soft_volume; + if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !data->volume_is_absolute) { + /* When the 'absolute' bool is not set then we'll treat the volume + * as relative to the sink volume even in flat volume mode */ + + pa_cvolume t = *pa_sink_get_volume(data->sink, FALSE); + pa_cvolume_remap(&t, &data->sink->channel_map, &data->channel_map); + + pa_sw_cvolume_multiply(&i->virtual_volume, &data->volume, &t); + } else + i->virtual_volume = data->volume; + + pa_cvolume_init(&i->soft_volume); i->save_volume = data->save_volume; i->save_sink = data->save_sink; i->save_muted = data->save_muted; @@ -330,7 +321,8 @@ pa_sink_input* pa_sink_input_new( /* Don't forget to call pa_sink_input_put! */ - return i; + *_i = i; + return 0; } /* Called from main context */ @@ -347,7 +339,7 @@ static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) { } /* Called from main context */ -static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) { +static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) { pa_sink_input *ssync; pa_assert(i); @@ -355,7 +347,7 @@ static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) { state = PA_SINK_INPUT_RUNNING; if (i->state == state) - return 0; + return; 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); @@ -382,8 +374,6 @@ static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) { } pa_sink_update_status(i->sink); - - return 0; } /* Called from main context */ @@ -499,9 +489,6 @@ void pa_sink_input_put(pa_sink_input *i) { pa_assert(i->process_rewind); pa_assert(i->kill); - i->thread_info.soft_volume = i->soft_volume; - i->thread_info.muted = i->muted; - state = i->flags & PA_SINK_INPUT_START_CORKED ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING; update_n_corked(i, state); @@ -512,7 +499,11 @@ void pa_sink_input_put(pa_sink_input *i) { pa_cvolume new_volume; pa_sink_update_flat_volume(i->sink, &new_volume); pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE); - } + } else + i->soft_volume = i->virtual_volume; + + i->thread_info.soft_volume = i->soft_volume; + i->thread_info.muted = i->muted; pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL) == 0); @@ -549,7 +540,7 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) { } /* Called from thread context */ -int pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa_memchunk *chunk, pa_cvolume *volume) { +void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa_memchunk *chunk, pa_cvolume *volume) { pa_bool_t do_volume_adj_here; pa_bool_t volume_is_norm; size_t block_size_max_sink, block_size_max_sink_input; @@ -563,9 +554,6 @@ int pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa /* pa_log_debug("peek"); */ - if (!i->pop) - return -1; - pa_assert(i->thread_info.state == PA_SINK_INPUT_RUNNING || i->thread_info.state == PA_SINK_INPUT_CORKED || i->thread_info.state == PA_SINK_INPUT_DRAINED); @@ -692,8 +680,6 @@ int pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa pa_cvolume_mute(volume, i->sink->sample_spec.channels); else *volume = i->thread_info.soft_volume; - - return 0; } /* Called from thread context */ @@ -960,7 +946,7 @@ void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) { int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - pa_return_val_if_fail(i->thread_info.resampler, -1); + pa_return_val_if_fail(i->thread_info.resampler, -PA_ERR_BADSTATE); if (i->sample_spec.rate == rate) return 0; @@ -1048,16 +1034,17 @@ pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) { int pa_sink_input_start_move(pa_sink_input *i) { pa_source_output *o, *p = NULL; pa_sink *origin; + int r; pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(i->sink); if (!pa_sink_input_may_move(i)) - return -1; + return -PA_ERR_NOTSUPPORTED; - if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], i) < 0) - return -1; + if ((r = pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], i)) < 0) + return r; origin = i->sink; @@ -1074,9 +1061,15 @@ int pa_sink_input_start_move(pa_sink_input *i) { if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED) pa_assert_se(i->sink->n_corked-- >= 1); - /* We might need to update the sink's volume if we are in flat volume mode. */ if (i->sink->flags & PA_SINK_FLAT_VOLUME) { pa_cvolume new_volume; + + /* Make the absolute volume relative */ + i->virtual_volume = i->soft_volume; + pa_cvolume_reset(&i->soft_volume, i->sample_spec.channels); + + /* We might need to update the sink's volume if we are in flat + * volume mode. */ pa_sink_update_flat_volume(i->sink, &new_volume); pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE); } @@ -1099,14 +1092,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { pa_sink_assert_ref(dest); if (!pa_sink_input_may_move_to(i, dest)) - return -1; - - i->sink = dest; - i->save_sink = save; - pa_idxset_put(dest->inputs, i, NULL); - - if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED) - i->sink->n_corked++; + return -PA_ERR_NOTSUPPORTED; if (i->thread_info.resampler && pa_sample_spec_equal(pa_resampler_output_sample_spec(i->thread_info.resampler), &dest->sample_spec) && @@ -1130,11 +1116,18 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { ((i->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | (i->core->disable_remixing || (i->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { pa_log_warn("Unsupported resampling operation."); - return -1; + return -PA_ERR_NOTSUPPORTED; } } else new_resampler = NULL; + i->sink = dest; + i->save_sink = save; + pa_idxset_put(dest->inputs, i, NULL); + + if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED) + i->sink->n_corked++; + /* Replace resampler and render queue */ if (new_resampler != i->thread_info.resampler) { @@ -1157,9 +1150,15 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { pa_sink_update_status(dest); - /* We might need to update the sink's volume if we are in flat volume mode. */ if (i->sink->flags & PA_SINK_FLAT_VOLUME) { pa_cvolume new_volume; + + /* Make relative volume absolute again */ + pa_cvolume t = dest->virtual_volume; + pa_cvolume_remap(&t, &dest->channel_map, &i->channel_map); + pa_sw_cvolume_multiply(&i->virtual_volume, &i->virtual_volume, &t); + + /* We might need to update the sink's volume if we are in flat volume mode. */ pa_sink_update_flat_volume(i->sink, &new_volume); pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE); } @@ -1180,6 +1179,8 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { /* Called from main context */ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { + int r; + pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(i->sink); @@ -1189,13 +1190,13 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { return 0; if (!pa_sink_input_may_move_to(i, dest)) - return -1; + return -PA_ERR_NOTSUPPORTED; - if (pa_sink_input_start_move(i) < 0) - return -1; + if ((r = pa_sink_input_start_move(i)) < 0) + return r; - if (pa_sink_input_finish_move(i, dest, save) < 0) - return -1; + if ((r = pa_sink_input_finish_move(i, dest, save)) < 0) + return r; return 0; } @@ -1310,7 +1311,7 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t } } - return -1; + return -PA_ERR_NOTIMPLEMENTED; } /* Called from main thread */ diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 893d8690..f6c5aa1d 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -58,6 +58,7 @@ typedef enum pa_sink_input_flags { PA_SINK_INPUT_FIX_RATE = 64, PA_SINK_INPUT_FIX_CHANNELS = 128, PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND = 256, + PA_SINK_INPUT_FAIL_ON_SUSPEND = 512 } pa_sink_input_flags_t; struct pa_sink_input { @@ -232,16 +233,16 @@ typedef struct pa_sink_input_new_data { pa_sample_spec sample_spec; pa_channel_map channel_map; - pa_cvolume virtual_volume, soft_volume; + pa_cvolume volume; pa_bool_t muted:1; pa_bool_t sample_spec_is_set:1; pa_bool_t channel_map_is_set:1; - pa_bool_t virtual_volume_is_set:1, soft_volume_is_set:1; + pa_bool_t volume_is_set:1; pa_bool_t muted_is_set:1; - pa_bool_t virtual_volume_is_absolute:1; + pa_bool_t volume_is_absolute:1; pa_bool_t save_sink:1, save_volume:1, save_muted:1; } pa_sink_input_new_data; @@ -249,14 +250,14 @@ typedef struct pa_sink_input_new_data { pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data); void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec); void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map); -void pa_sink_input_new_data_set_soft_volume(pa_sink_input_new_data *data, const pa_cvolume *volume); -void pa_sink_input_new_data_set_virtual_volume(pa_sink_input_new_data *data, const pa_cvolume *volume); +void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume); void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute); void pa_sink_input_new_data_done(pa_sink_input_new_data *data); /* To be called by the implementing module only */ -pa_sink_input* pa_sink_input_new( +int pa_sink_input_new( + pa_sink_input **i, pa_core *core, pa_sink_input_new_data *data, pa_sink_input_flags_t flags); @@ -312,7 +313,7 @@ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i); /* To be used exclusively by the sink driver IO thread */ -int pa_sink_input_peek(pa_sink_input *i, size_t length, pa_memchunk *chunk, pa_cvolume *volume); +void pa_sink_input_peek(pa_sink_input *i, size_t length, pa_memchunk *chunk, pa_cvolume *volume); 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 */); diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 61be86a1..0c297ec3 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -305,6 +305,11 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { s->state = state; + if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */ + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s); + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + } + if (suspend_change) { pa_sink_input *i; uint32_t idx; @@ -312,15 +317,13 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { /* We're suspending or resuming, tell everyone about it */ for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) - if (i->suspend) + if (s->state == PA_SINK_SUSPENDED && + (i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND)) + pa_sink_input_kill(i); + else if (i->suspend) i->suspend(i, state == PA_SINK_SUSPENDED); } - if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */ - pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index); - } - return 0; } @@ -544,9 +547,17 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) { pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); + /* If nobody requested this and this is actually no real rewind + * then we can short cut this */ + if (!s->thread_info.rewind_requested && nbytes <= 0) + return; + s->thread_info.rewind_nbytes = 0; s->thread_info.rewind_requested = FALSE; + if (s->thread_info.state == PA_SINK_SUSPENDED) + return; + if (nbytes > 0) pa_log_debug("Processing rewind..."); @@ -556,7 +567,7 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) { } if (nbytes > 0) - if (s->monitor_source && PA_SOURCE_IS_OPENED(s->monitor_source->thread_info.state)) + if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) pa_source_process_rewind(s->monitor_source, nbytes); } @@ -573,8 +584,7 @@ static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, uns while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) { pa_sink_input_assert_ref(i); - if (pa_sink_input_peek(i, *length, &info->chunk, &info->volume) < 0) - continue; + pa_sink_input_peek(i, *length, &info->chunk, &info->volume); if (mixlength == 0 || info->chunk.length < mixlength) mixlength = info->chunk.length; @@ -636,7 +646,7 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk * /* Drop read data */ pa_sink_input_drop(i, result->length); - if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) { + if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) { if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) { void *ostate = NULL; @@ -692,7 +702,7 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk * } } - if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) + if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) pa_source_post(s->monitor_source, result); } @@ -703,7 +713,7 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { size_t block_size_max; pa_sink_assert_ref(s); - pa_assert(PA_SINK_IS_OPENED(s->thread_info.state)); + pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); pa_assert(pa_frame_aligned(length, &s->sample_spec)); pa_assert(result); @@ -712,6 +722,13 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_assert(!s->thread_info.rewind_requested); pa_assert(s->thread_info.rewind_nbytes == 0); + if (s->thread_info.state == PA_SINK_SUSPENDED) { + result->memblock = pa_memblock_ref(s->silence.memblock); + result->index = s->silence.index; + result->length = PA_MIN(s->silence.length, length); + return; + } + if (length <= 0) length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec); @@ -776,7 +793,7 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) { size_t length, block_size_max; pa_sink_assert_ref(s); - pa_assert(PA_SINK_IS_OPENED(s->thread_info.state)); + pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); pa_assert(target); pa_assert(target->memblock); pa_assert(target->length > 0); @@ -787,6 +804,11 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_assert(!s->thread_info.rewind_requested); pa_assert(s->thread_info.rewind_nbytes == 0); + if (s->thread_info.state == PA_SINK_SUSPENDED) { + pa_silence_memchunk(target, &s->sample_spec); + return; + } + length = target->length; block_size_max = pa_mempool_block_size_max(s->core->mempool); if (length > block_size_max) @@ -854,7 +876,7 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { size_t l, d; pa_sink_assert_ref(s); - pa_assert(PA_SINK_IS_OPENED(s->thread_info.state)); + pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); pa_assert(target); pa_assert(target->memblock); pa_assert(target->length > 0); @@ -884,7 +906,7 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { /* 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)); + pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); pa_assert(length > 0); pa_assert(pa_frame_aligned(length, &s->sample_spec)); pa_assert(result); @@ -910,7 +932,7 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) { /* The returned value is supposed to be in the time domain of the sound card! */ - if (!PA_SINK_IS_OPENED(s->state)) + if (s->state == PA_SINK_SUSPENDED) return 0; if (!(s->flags & PA_SINK_LATENCY)) @@ -926,12 +948,24 @@ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) { pa_sink_input *i; uint32_t idx; + pa_sink_assert_ref(s); + pa_assert(new_volume); + pa_assert(PA_SINK_IS_LINKED(s->state)); + pa_assert(s->flags & PA_SINK_FLAT_VOLUME); + /* This is called whenever a sink input volume changes and we * might need to fix up the sink volume accordingly. Please note * that we don't actually update the sinks volume here, we only * return how it needs to be updated. The caller should then call * pa_sink_set_flat_volume().*/ + if (pa_idxset_isempty(s->inputs)) { + /* In the special case that we have no sink input we leave the + * volume unmodified. */ + *new_volume = s->virtual_volume; + return; + } + pa_cvolume_mute(new_volume, s->channel_map.channels); /* First let's determine the new maximum volume of all inputs @@ -973,8 +1007,8 @@ void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) { uint32_t idx; pa_sink_assert_ref(s); - pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(old_volume); + pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(s->flags & PA_SINK_FLAT_VOLUME); /* This is called whenever the sink volume changes that is not @@ -1133,6 +1167,7 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) { pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) { pa_sink_assert_ref(s); + pa_assert(p); pa_proplist_update(s->proplist, mode, p); @@ -1473,7 +1508,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse case PA_SINK_MESSAGE_SET_MUTE: - if (!s->thread_info.soft_muted != s->muted) { + if (s->thread_info.soft_muted != s->muted) { s->thread_info.soft_muted = s->muted; pa_sink_request_rewind(s, (size_t) -1); } @@ -1486,6 +1521,10 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse case PA_SINK_MESSAGE_SET_STATE: s->thread_info.state = PA_PTR_TO_UINT(userdata); + + if (s->thread_info.state == PA_SINK_SUSPENDED) + s->thread_info.rewind_requested = FALSE; + return 0; case PA_SINK_MESSAGE_DETACH: @@ -1613,6 +1652,9 @@ 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)); + if (s->thread_info.state == PA_SINK_SUSPENDED) + return; + if (nbytes == (size_t) -1) nbytes = s->thread_info.max_rewind; @@ -1674,7 +1716,7 @@ pa_usec_t pa_sink_get_requested_latency(pa_sink *s) { pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); - if (!PA_SINK_IS_OPENED(s->state)) + if (s->state == PA_SINK_SUSPENDED) return 0; pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 1be421f1..c3de3067 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -322,11 +322,11 @@ int pa_play_file( data.sink = sink; data.driver = __FILE__; pa_sink_input_new_data_set_sample_spec(&data, &ss); - pa_sink_input_new_data_set_virtual_volume(&data, volume); + pa_sink_input_new_data_set_volume(&data, volume); 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); + pa_sink_input_new(&u->sink_input, sink->core, &data, 0); pa_sink_input_new_data_done(&data); if (!u->sink_input) diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 1e1ac4e1..63d56d5a 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -95,7 +95,8 @@ static void reset_callbacks(pa_source_output *o) { } /* Called from main context */ -pa_source_output* pa_source_output_new( +int pa_source_output_new( + pa_source_output**_o, pa_core *core, pa_source_output_new_data *data, pa_source_output_flags_t flags) { @@ -103,29 +104,34 @@ pa_source_output* pa_source_output_new( pa_source_output *o; pa_resampler *resampler = NULL; char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + int r; + pa_assert(_o); pa_assert(core); pa_assert(data); - if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data) < 0) - return NULL; + if (data->client) + pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist); - pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver)); + if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data)) < 0) + return r; + + pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID); if (!data->source) { data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE); data->save_source = FALSE; } - 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); + pa_return_val_if_fail(data->source, -PA_ERR_NOENTITY); + pa_return_val_if_fail(PA_SOURCE_IS_LINKED(pa_source_get_state(data->source)), -PA_ERR_BADSTATE); + pa_return_val_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of, -PA_ERR_INVALID); + pa_return_val_if_fail(!(flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND) || pa_source_get_state(data->source) != PA_SOURCE_SUSPENDED, -PA_ERR_BADSTATE); if (!data->sample_spec_is_set) data->sample_spec = data->source->sample_spec; - pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec)); + pa_return_val_if_fail(pa_sample_spec_valid(&data->sample_spec), -PA_ERR_INVALID); if (!data->channel_map_is_set) { if (pa_channel_map_compatible(&data->source->channel_map, &data->sample_spec)) @@ -134,8 +140,8 @@ pa_source_output* pa_source_output_new( pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); } - pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); - pa_return_null_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec)); + pa_return_val_if_fail(pa_channel_map_valid(&data->channel_map), -PA_ERR_INVALID); + pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID); if (flags & PA_SOURCE_OUTPUT_FIX_FORMAT) data->sample_spec.format = data->source->sample_spec.format; @@ -154,17 +160,14 @@ pa_source_output* pa_source_output_new( if (data->resample_method == PA_RESAMPLER_INVALID) data->resample_method = core->resample_method; - pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX); + pa_return_val_if_fail(data->resample_method < PA_RESAMPLER_MAX, -PA_ERR_INVALID); - if (data->client) - pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist); - - if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data) < 0) - return NULL; + if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data)) < 0) + return r; if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log("Failed to create source output: too many outputs per source."); - return NULL; + return -PA_ERR_TOOLARGE; } if ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) || @@ -181,7 +184,7 @@ pa_source_output* pa_source_output_new( (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) | (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) { pa_log_warn("Unsupported resampling operation."); - return NULL; + return -PA_ERR_NOTSUPPORTED; } } @@ -245,7 +248,8 @@ pa_source_output* pa_source_output_new( /* Don't forget to call pa_source_output_put! */ - return o; + *_o = o; + return 0; } /* Called from main context */ @@ -262,11 +266,11 @@ static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) } /* Called from main context */ -static int source_output_set_state(pa_source_output *o, pa_source_output_state_t state) { +static void source_output_set_state(pa_source_output *o, pa_source_output_state_t state) { pa_assert(o); if (o->state == state) - return 0; + return; 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); @@ -277,8 +281,6 @@ static int source_output_set_state(pa_source_output *o, pa_source_output_state_t pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], o); pa_source_update_status(o->source); - - return 0; } /* Called from main context */ @@ -575,7 +577,7 @@ void pa_source_output_cork(pa_source_output *o, pa_bool_t b) { int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) { pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); - pa_return_val_if_fail(o->thread_info.resampler, -1); + pa_return_val_if_fail(o->thread_info.resampler, -PA_ERR_BADSTATE); if (o->sample_spec.rate == rate) return 0; @@ -675,16 +677,17 @@ pa_bool_t pa_source_output_may_move_to(pa_source_output *o, pa_source *dest) { /* Called from main context */ int pa_source_output_start_move(pa_source_output *o) { pa_source *origin; + int r; pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_assert(o->source); if (!pa_source_output_may_move(o)) - return -1; + return -PA_ERR_NOTSUPPORTED; - if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], o) < 0) - return -1; + if ((r = pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], o)) < 0) + return r; origin = o->source; @@ -713,13 +716,6 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t if (!pa_source_output_may_move_to(o, dest)) return -1; - o->source = dest; - o->save_source = save; - pa_idxset_put(o->source->outputs, o, NULL); - - if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) - o->source->n_corked++; - if (o->thread_info.resampler && pa_sample_spec_equal(pa_resampler_input_sample_spec(o->thread_info.resampler), &dest->sample_spec) && pa_channel_map_equal(pa_resampler_input_channel_map(o->thread_info.resampler), &dest->channel_map)) @@ -742,11 +738,18 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { pa_log_warn("Unsupported resampling operation."); - return -1; + return -PA_ERR_NOTSUPPORTED; } } else new_resampler = NULL; + o->source = dest; + o->save_source = save; + pa_idxset_put(o->source->outputs, o, NULL); + + if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) + o->source->n_corked++; + /* Replace resampler */ if (new_resampler != o->thread_info.resampler) { if (o->thread_info.resampler) @@ -783,6 +786,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t /* Called from main context */ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t save) { + int r; pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); @@ -793,13 +797,13 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav return 0; if (!pa_source_output_may_move_to(o, dest)) - return -1; + return -PA_ERR_NOTSUPPORTED; - if (pa_source_output_start_move(o) < 0) - return -1; + if ((r = pa_source_output_start_move(o)) < 0) + return r; - if (pa_source_output_finish_move(o, dest, save) < 0) - return -1; + if ((r = pa_source_output_finish_move(o, dest, save)) < 0) + return r; return 0; } @@ -863,5 +867,5 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int } } - return -1; + return -PA_ERR_NOTIMPLEMENTED; } diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 79b4926b..91f28f94 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -54,7 +54,8 @@ typedef enum pa_source_output_flags { PA_SOURCE_OUTPUT_FIX_FORMAT = 32, PA_SOURCE_OUTPUT_FIX_RATE = 64, PA_SOURCE_OUTPUT_FIX_CHANNELS = 128, - PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND = 256 + PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND = 256, + PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND = 512 } pa_source_output_flags_t; struct pa_source_output { @@ -204,7 +205,8 @@ void pa_source_output_new_data_done(pa_source_output_new_data *data); /* To be called by the implementing module only */ -pa_source_output* pa_source_output_new( +int pa_source_output_new( + pa_source_output**o, pa_core *core, pa_source_output_new_data *data, pa_source_output_flags_t flags); diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 38f8e531..04c7f8b7 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -267,6 +267,11 @@ static int source_set_state(pa_source *s, pa_source_state_t state) { s->state = state; + if (state != PA_SOURCE_UNLINKED) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */ + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s); + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + } + if (suspend_change) { pa_source_output *o; uint32_t idx; @@ -274,12 +279,13 @@ static int source_set_state(pa_source *s, pa_source_state_t state) { /* We're suspending or resuming, tell everyone about it */ for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) - if (o->suspend) + if (s->state == PA_SOURCE_SUSPENDED && + (o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND)) + pa_source_output_kill(o); + else if (o->suspend) o->suspend(o, state == PA_SOURCE_SUSPENDED); } - if (state != PA_SOURCE_UNLINKED) /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */ - pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s); return 0; } @@ -479,7 +485,10 @@ void pa_source_process_rewind(pa_source *s, size_t nbytes) { void *state = NULL; pa_source_assert_ref(s); - pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state)); + pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); + + if (s->thread_info.state == PA_SOURCE_SUSPENDED) + return; if (nbytes <= 0) return; @@ -498,9 +507,12 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { void *state = NULL; pa_source_assert_ref(s); - pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state)); + pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); pa_assert(chunk); + if (s->thread_info.state == PA_SOURCE_SUSPENDED) + return; + if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) { pa_memchunk vchunk = *chunk; @@ -534,11 +546,14 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { /* Called from IO thread context */ void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) { pa_source_assert_ref(s); - pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state)); + pa_assert(PA_SOURCE_IS_LINKED(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_SUSPENDED) + return; + if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) { pa_memchunk vchunk = *chunk; @@ -564,7 +579,7 @@ pa_usec_t pa_source_get_latency(pa_source *s) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); - if (!PA_SOURCE_IS_OPENED(s->state)) + if (s->state == PA_SOURCE_SUSPENDED) return 0; if (!(s->flags & PA_SOURCE_LATENCY)) @@ -675,8 +690,8 @@ pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) { /* Called from main thread */ pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) { - pa_source_assert_ref(s); + pa_assert(p); pa_proplist_update(s->proplist, mode, p); @@ -1000,7 +1015,7 @@ pa_usec_t pa_source_get_requested_latency(pa_source *s) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); - if (!PA_SOURCE_IS_OPENED(s->state)) + if (s->state == PA_SOURCE_SUSPENDED) return 0; pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); |