summaryrefslogtreecommitdiffstats
path: root/src/pulsecore
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulsecore')
-rw-r--r--src/pulsecore/cli-text.c8
-rw-r--r--src/pulsecore/core-util.c47
-rw-r--r--src/pulsecore/core-util.h4
-rw-r--r--src/pulsecore/envelope.c8
-rw-r--r--src/pulsecore/idxset.c42
-rw-r--r--src/pulsecore/ltdl-helper.c6
-rw-r--r--src/pulsecore/macro.h16
-rw-r--r--src/pulsecore/modargs.c179
-rw-r--r--src/pulsecore/namereg.c2
-rw-r--r--src/pulsecore/play-memblockq.c4
-rw-r--r--src/pulsecore/proplist-util.c63
-rw-r--r--src/pulsecore/protocol-esound.c4
-rw-r--r--src/pulsecore/protocol-native.c51
-rw-r--r--src/pulsecore/protocol-simple.c4
-rw-r--r--src/pulsecore/resampler.c12
-rw-r--r--src/pulsecore/sink-input.c179
-rw-r--r--src/pulsecore/sink-input.h15
-rw-r--r--src/pulsecore/sink.c80
-rw-r--r--src/pulsecore/sound-file-stream.c4
-rw-r--r--src/pulsecore/source-output.c88
-rw-r--r--src/pulsecore/source-output.h6
-rw-r--r--src/pulsecore/source.c33
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);