summaryrefslogtreecommitdiffstats
path: root/src/pulse
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulse')
-rw-r--r--src/pulse/channelmap.c141
-rw-r--r--src/pulse/channelmap.h5
-rw-r--r--src/pulse/def.h1
-rw-r--r--src/pulse/introspect.c210
-rw-r--r--src/pulse/introspect.h36
-rw-r--r--src/pulse/proplist.h3
-rw-r--r--src/pulse/version.h.in4
-rw-r--r--src/pulse/volume.c88
-rw-r--r--src/pulse/volume.h12
-rw-r--r--src/pulse/xmalloc.h13
10 files changed, 350 insertions, 163 deletions
diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c
index 4654a9ad..88823012 100644
--- a/src/pulse/channelmap.c
+++ b/src/pulse/channelmap.c
@@ -30,9 +30,11 @@
#include <pulse/xmalloc.h>
#include <pulse/i18n.h>
+
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
#include <pulsecore/bitset.h>
+#include <pulsecore/sample-util.h>
#include "channelmap.h"
@@ -491,6 +493,27 @@ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
return s;
}
+pa_channel_position_t pa_channel_position_from_string(const char *p) {
+ pa_channel_position_t i;
+ pa_assert(p);
+
+ /* Some special aliases */
+ if (pa_streq(p, "left"))
+ return PA_CHANNEL_POSITION_LEFT;
+ else if (pa_streq(p, "right"))
+ return PA_CHANNEL_POSITION_RIGHT;
+ else if (pa_streq(p, "center"))
+ return PA_CHANNEL_POSITION_CENTER;
+ else if (pa_streq(p, "subwoofer"))
+ return PA_CHANNEL_POSITION_SUBWOOFER;
+
+ for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
+ if (pa_streq(p, table[i]))
+ return i;
+
+ return PA_CHANNEL_POSITION_INVALID;
+}
+
pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
const char *state;
pa_channel_map map;
@@ -559,36 +582,19 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
map.channels = 0;
while ((p = pa_split(s, ",", &state))) {
+ pa_channel_position_t f;
if (map.channels >= PA_CHANNELS_MAX) {
pa_xfree(p);
return NULL;
}
- /* Some special aliases */
- if (pa_streq(p, "left"))
- map.map[map.channels++] = PA_CHANNEL_POSITION_LEFT;
- else if (pa_streq(p, "right"))
- map.map[map.channels++] = PA_CHANNEL_POSITION_RIGHT;
- else if (pa_streq(p, "center"))
- map.map[map.channels++] = PA_CHANNEL_POSITION_CENTER;
- else if (pa_streq(p, "subwoofer"))
- map.map[map.channels++] = PA_CHANNEL_POSITION_SUBWOOFER;
- else {
- pa_channel_position_t i;
-
- for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
- if (strcmp(p, table[i]) == 0) {
- map.map[map.channels++] = i;
- break;
- }
-
- if (i >= PA_CHANNEL_POSITION_MAX) {
- pa_xfree(p);
- return NULL;
- }
+ if ((f = pa_channel_position_from_string(p)) == PA_CHANNEL_POSITION_INVALID) {
+ pa_xfree(p);
+ return NULL;
}
+ map.map[map.channels++] = f;
pa_xfree(p);
}
@@ -627,8 +633,7 @@ int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *s
}
int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
- pa_bitset_t in_a[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
- unsigned i;
+ pa_channel_position_mask_t am, bm;
pa_assert(a);
pa_assert(b);
@@ -636,98 +641,36 @@ int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
pa_return_val_if_fail(pa_channel_map_valid(a), 0);
pa_return_val_if_fail(pa_channel_map_valid(b), 0);
- memset(in_a, 0, sizeof(in_a));
+ am = pa_channel_map_mask(a);
+ bm = pa_channel_map_mask(b);
- for (i = 0; i < a->channels; i++)
- pa_bitset_set(in_a, a->map[i], TRUE);
-
- for (i = 0; i < b->channels; i++)
- if (!pa_bitset_get(in_a, b->map[i]))
- return 0;
-
- return 1;
+ return (bm & am) == bm;
}
int pa_channel_map_can_balance(const pa_channel_map *map) {
- unsigned c;
- pa_bool_t left = FALSE, right = FALSE;
+ pa_channel_position_mask_t m;
pa_assert(map);
-
pa_return_val_if_fail(pa_channel_map_valid(map), 0);
- for (c = 0; c < map->channels; c++) {
-
- switch (map->map[c]) {
- case PA_CHANNEL_POSITION_LEFT:
- case PA_CHANNEL_POSITION_REAR_LEFT:
- case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
- case PA_CHANNEL_POSITION_SIDE_LEFT:
- case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
- case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
- left = TRUE;
- break;
-
- case PA_CHANNEL_POSITION_RIGHT:
- case PA_CHANNEL_POSITION_REAR_RIGHT:
- case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
- case PA_CHANNEL_POSITION_SIDE_RIGHT:
- case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
- case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
- right = TRUE;
- break;
-
- default:
- ;
- }
-
- if (left && right)
- return 1;
- }
+ m = pa_channel_map_mask(map);
- return 0;
+ return
+ (PA_CHANNEL_POSITION_MASK_LEFT & m) &&
+ (PA_CHANNEL_POSITION_MASK_RIGHT & m);
}
int pa_channel_map_can_fade(const pa_channel_map *map) {
- unsigned c;
- pa_bool_t front = FALSE, rear = FALSE;
+ pa_channel_position_mask_t m;
pa_assert(map);
-
pa_return_val_if_fail(pa_channel_map_valid(map), 0);
- for (c = 0; c < map->channels; c++) {
-
- switch (map->map[c]) {
- case PA_CHANNEL_POSITION_FRONT_LEFT:
- case PA_CHANNEL_POSITION_FRONT_RIGHT:
- case PA_CHANNEL_POSITION_FRONT_CENTER:
- case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
- case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
- case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
- case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
- case PA_CHANNEL_POSITION_TOP_FRONT_CENTER:
- front = TRUE;
- break;
-
- case PA_CHANNEL_POSITION_REAR_LEFT:
- case PA_CHANNEL_POSITION_REAR_RIGHT:
- case PA_CHANNEL_POSITION_REAR_CENTER:
- case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
- case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
- case PA_CHANNEL_POSITION_TOP_REAR_CENTER:
- rear = TRUE;
- break;
-
- default:
- ;
- }
-
- if (front && rear)
- return 1;
- }
+ m = pa_channel_map_mask(map);
- return 0;
+ return
+ (PA_CHANNEL_POSITION_MASK_FRONT & m) &&
+ (PA_CHANNEL_POSITION_MASK_REAR & m);
}
const char* pa_channel_map_to_name(const pa_channel_map *map) {
diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h
index 2aaead01..d7901ac2 100644
--- a/src/pulse/channelmap.h
+++ b/src/pulse/channelmap.h
@@ -209,7 +209,7 @@ typedef enum pa_channel_position {
typedef uint64_t pa_channel_position_mask_t;
/** Makes a bit mask from a channel position. \since 0.9.16 */
-#define PA_CHANNEL_POSITION_MASK(f) ((pa_channel_position_mask_t) (1 << (f)))
+#define PA_CHANNEL_POSITION_MASK(f) ((pa_channel_position_mask_t) (1ULL << (f)))
/** A list of channel mapping definitions for pa_channel_map_init_auto() */
typedef enum pa_channel_map_def {
@@ -282,6 +282,9 @@ pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels,
/** Return a text label for the specified channel position */
const char* pa_channel_position_to_string(pa_channel_position_t pos) PA_GCC_PURE;
+/* The inverse of pa_channel_position_to_string(). \since 0.9.16 */
+pa_channel_position_t pa_channel_position_from_string(const char *s) PA_GCC_PURE;
+
/** Return a human readable text label for the specified channel position. \since 0.9.7 */
const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos);
diff --git a/src/pulse/def.h b/src/pulse/def.h
index d5bbefe3..08399ca8 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -393,6 +393,7 @@ enum {
PA_ERR_OBSOLETE, /**< Obsolete functionality. \since 0.9.15 */
PA_ERR_NOTIMPLEMENTED, /**< Missing implementation. \since 0.9.15 */
PA_ERR_FORKED, /**< The caller forked without calling execve() and tried to reuse the context. \since 0.9.15 */
+ PA_ERR_IO, /**< An IO error happened. \since 0.9.16 */
PA_ERR_MAX /**< Not really an error but the first invalid error code */
};
diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
index ac8a11aa..ab67f596 100644
--- a/src/pulse/introspect.c
+++ b/src/pulse/introspect.c
@@ -49,7 +49,7 @@ static void context_stat_callback(pa_pdispatch *pd, uint32_t command, uint32_t t
pa_assert(o);
pa_assert(PA_REFCNT_VALUE(o) >= 1);
- memset(&i, 0, sizeof(i));
+ pa_zero(i);
if (!o->context)
goto finish;
@@ -93,7 +93,7 @@ static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command,
pa_assert(o);
pa_assert(PA_REFCNT_VALUE(o) >= 1);
- memset(&i, 0, sizeof(i));
+ pa_zero(i);
if (!o->context)
goto finish;
@@ -161,8 +161,10 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u
pa_bool_t mute;
uint32_t flags;
uint32_t state;
+ uint32_t j;
+ const char *ap = NULL;
- memset(&i, 0, sizeof(i));
+ pa_zero(i);
i.proplist = pa_proplist_new();
i.base_volume = PA_VOLUME_NORM;
i.n_volume_steps = PA_VOLUME_NORM+1;
@@ -190,13 +192,53 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u
(pa_tagstruct_get_volume(t, &i.base_volume) < 0 ||
pa_tagstruct_getu32(t, &state) < 0 ||
pa_tagstruct_getu32(t, &i.n_volume_steps) < 0 ||
- pa_tagstruct_getu32(t, &i.card) < 0))) {
+ pa_tagstruct_getu32(t, &i.card) < 0)) ||
+ (o->context->version >= 16 &&
+ (pa_tagstruct_getu32(t, &i.n_ports)))) {
+
+ pa_context_fail(o->context, PA_ERR_PROTOCOL);
+ pa_proplist_free(i.proplist);
+ goto finish;
+ }
+
+ if (i.n_ports > 0) {
+ i.ports = pa_xnew(pa_sink_port_info*, i.n_ports+1);
+ i.ports[0] = pa_xnew(pa_sink_port_info, i.n_ports);
+
+ for (j = 0; j < i.n_ports; j++) {
+ if (pa_tagstruct_gets(t, &i.ports[0][j].name) < 0 ||
+ pa_tagstruct_gets(t, &i.ports[0][j].description) < 0 ||
+ pa_tagstruct_getu32(t, &i.ports[0][j].priority) < 0) {
+
+ pa_context_fail(o->context, PA_ERR_PROTOCOL);
+ pa_xfree(i.ports);
+ pa_xfree(i.ports[0]);
+ pa_proplist_free(i.proplist);
+ goto finish;
+ }
+
+ i.ports[j] = &i.ports[0][j];
+ }
+
+ i.ports[j] = NULL;
+ }
+ if (pa_tagstruct_gets(t, &ap) < 0) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
+ pa_xfree(i.ports[0]);
+ pa_xfree(i.ports);
pa_proplist_free(i.proplist);
goto finish;
}
+ if (ap) {
+ for (j = 0; j < i.n_ports; j++)
+ if (pa_streq(i.ports[j]->name, ap)) {
+ i.active_port = i.ports[j];
+ break;
+ }
+ }
+
i.mute = (int) mute;
i.flags = (pa_sink_flags_t) flags;
i.state = (pa_sink_state_t) state;
@@ -271,6 +313,56 @@ pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name,
return o;
}
+pa_operation* pa_context_set_sink_port_by_index(pa_context *c, uint32_t idx, const char*port, pa_context_success_cb_t cb, void *userdata) {
+ pa_operation *o;
+ pa_tagstruct *t;
+ uint32_t tag;
+
+ pa_assert(c);
+ pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+ PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 16, PA_ERR_NOTSUPPORTED);
+
+ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+ t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_PORT, &tag);
+ pa_tagstruct_putu32(t, idx);
+ pa_tagstruct_puts(t, NULL);
+ pa_tagstruct_puts(t, port);
+ pa_pstream_send_tagstruct(c->pstream, t);
+ pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+ return o;
+}
+
+pa_operation* pa_context_set_sink_port_by_name(pa_context *c, const char *name, const char*port, pa_context_success_cb_t cb, void *userdata) {
+ pa_operation *o;
+ pa_tagstruct *t;
+ uint32_t tag;
+
+ pa_assert(c);
+ pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+ PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 16, PA_ERR_NOTSUPPORTED);
+
+ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+ t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_PORT, &tag);
+ pa_tagstruct_putu32(t, PA_INVALID_INDEX);
+ pa_tagstruct_puts(t, name);
+ pa_tagstruct_puts(t, port);
+ pa_pstream_send_tagstruct(c->pstream, t);
+ pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+ return o;
+}
+
/*** Source info ***/
static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
@@ -296,8 +388,10 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
pa_bool_t mute;
uint32_t flags;
uint32_t state;
+ unsigned j;
+ const char *ap;
- memset(&i, 0, sizeof(i));
+ pa_zero(i);
i.proplist = pa_proplist_new();
i.base_volume = PA_VOLUME_NORM;
i.n_volume_steps = PA_VOLUME_NORM+1;
@@ -325,13 +419,53 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
(pa_tagstruct_get_volume(t, &i.base_volume) < 0 ||
pa_tagstruct_getu32(t, &state) < 0 ||
pa_tagstruct_getu32(t, &i.n_volume_steps) < 0 ||
- pa_tagstruct_getu32(t, &i.card) < 0))) {
+ pa_tagstruct_getu32(t, &i.card) < 0)) ||
+ (o->context->version >= 16 &&
+ (pa_tagstruct_getu32(t, &i.n_ports)))) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
pa_proplist_free(i.proplist);
goto finish;
}
+ if (i.n_ports > 0) {
+ i.ports = pa_xnew(pa_source_port_info*, i.n_ports+1);
+ i.ports[0] = pa_xnew(pa_source_port_info, i.n_ports);
+
+ for (j = 0; j < i.n_ports; j++) {
+ if (pa_tagstruct_gets(t, &i.ports[0][j].name) < 0 ||
+ pa_tagstruct_gets(t, &i.ports[0][j].description) < 0 ||
+ pa_tagstruct_getu32(t, &i.ports[0][j].priority) < 0) {
+
+ pa_context_fail(o->context, PA_ERR_PROTOCOL);
+ pa_xfree(i.ports[0]);
+ pa_xfree(i.ports);
+ pa_proplist_free(i.proplist);
+ goto finish;
+ }
+
+ i.ports[j] = &i.ports[0][j];
+ }
+
+ i.ports[j] = NULL;
+ }
+
+ if (pa_tagstruct_gets(t, &ap) < 0) {
+ pa_context_fail(o->context, PA_ERR_PROTOCOL);
+ pa_xfree(i.ports[0]);
+ pa_xfree(i.ports);
+ pa_proplist_free(i.proplist);
+ goto finish;
+ }
+
+ if (ap) {
+ for (j = 0; j < i.n_ports; j++)
+ if (pa_streq(i.ports[j]->name, ap)) {
+ i.active_port = i.ports[j];
+ break;
+ }
+ }
+
i.mute = (int) mute;
i.flags = (pa_source_flags_t) flags;
i.state = (pa_source_state_t) state;
@@ -406,6 +540,56 @@ pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name
return o;
}
+pa_operation* pa_context_set_source_port_by_index(pa_context *c, uint32_t idx, const char*port, pa_context_success_cb_t cb, void *userdata) {
+ pa_operation *o;
+ pa_tagstruct *t;
+ uint32_t tag;
+
+ pa_assert(c);
+ pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+ PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 16, PA_ERR_NOTSUPPORTED);
+
+ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+ t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_PORT, &tag);
+ pa_tagstruct_putu32(t, idx);
+ pa_tagstruct_puts(t, NULL);
+ pa_tagstruct_puts(t, port);
+ pa_pstream_send_tagstruct(c->pstream, t);
+ pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+ return o;
+}
+
+pa_operation* pa_context_set_source_port_by_name(pa_context *c, const char *name, const char*port, pa_context_success_cb_t cb, void *userdata) {
+ pa_operation *o;
+ pa_tagstruct *t;
+ uint32_t tag;
+
+ pa_assert(c);
+ pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+ PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 16, PA_ERR_NOTSUPPORTED);
+
+ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+ t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_PORT, &tag);
+ pa_tagstruct_putu32(t, PA_INVALID_INDEX);
+ pa_tagstruct_puts(t, name);
+ pa_tagstruct_puts(t, port);
+ pa_pstream_send_tagstruct(c->pstream, t);
+ pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+ return o;
+}
+
/*** Client info ***/
static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
@@ -429,7 +613,7 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command,
while (!pa_tagstruct_eof(t)) {
pa_client_info i;
- memset(&i, 0, sizeof(i));
+ pa_zero(i);
i.proplist = pa_proplist_new();
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
@@ -514,7 +698,7 @@ static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, u
uint32_t j;
const char*ap;
- memset(&i, 0, sizeof(i));
+ pa_zero(i);
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 0 ||
@@ -527,7 +711,7 @@ static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, u
}
if (i.n_profiles > 0) {
- i.profiles = pa_xnew(pa_card_profile_info, i.n_profiles+1);
+ i.profiles = pa_xnew0(pa_card_profile_info, i.n_profiles+1);
for (j = 0; j < i.n_profiles; j++) {
@@ -715,7 +899,7 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command,
pa_module_info i;
pa_bool_t auto_unload = FALSE;
- memset(&i, 0, sizeof(i));
+ pa_zero(i);
i.proplist = pa_proplist_new();
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
@@ -800,7 +984,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm
pa_sink_input_info i;
pa_bool_t mute = FALSE;
- memset(&i, 0, sizeof(i));
+ pa_zero(i);
i.proplist = pa_proplist_new();
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
@@ -894,7 +1078,7 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c
while (!pa_tagstruct_eof(t)) {
pa_source_output_info i;
- memset(&i, 0, sizeof(i));
+ pa_zero(i);
i.proplist = pa_proplist_new();
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
@@ -1236,7 +1420,7 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command,
pa_sample_info i;
pa_bool_t lazy = FALSE;
- memset(&i, 0, sizeof(i));
+ pa_zero(i);
i.proplist = pa_proplist_new();
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index 117880c8..ee982100 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -193,6 +193,15 @@ PA_C_DECL_BEGIN
/** @{ \name Sinks */
+/** Stores information about a specific port of a sink. Please
+ * note that this structure can be extended as part of evolutionary
+ * API updates at any time in any new release. \since 0.9.16 */
+typedef struct pa_sink_port_info {
+ const char *name; /**< Name of this port */
+ const char *description; /**< Description of this port */
+ uint32_t priority; /**< The higher this value is the more useful this port is as a default */
+} pa_sink_port_info;
+
/** Stores information about sinks. Please note that this structure
* can be extended as part of evolutionary API updates at any time in
* any new release. */
@@ -216,6 +225,9 @@ typedef struct pa_sink_info {
pa_sink_state_t state; /**< State \since 0.9.15 */
uint32_t n_volume_steps; /**< Number of volume steps for sinks which do not support arbitrary volumes. \since 0.9.15 */
uint32_t card; /**< Card index, or PA_INVALID_INDEX. \since 0.9.15 */
+ uint32_t n_ports; /**< Number of entries in port array \since 0.9.16 */
+ pa_sink_port_info** ports; /**< Array of available ports, or NULL. Array is terminated by an entry set to NULL. The number of entries is stored in n_ports \since 0.9.16 */
+ pa_sink_port_info* active_port; /**< Pointer to active port in the array, or NULL \since 0.9.16 */
} pa_sink_info;
/** Callback prototype for pa_context_get_sink_info_by_name() and friends */
@@ -248,10 +260,25 @@ pa_operation* pa_context_suspend_sink_by_name(pa_context *c, const char *sink_na
/** Suspend/Resume a sink. If idx is PA_INVALID_INDEX all sinks will be suspended. \since 0.9.7 */
pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata);
+/** Change the profile of a sink. \since 0.9.16 */
+pa_operation* pa_context_set_sink_port_by_index(pa_context *c, uint32_t idx, const char*port, pa_context_success_cb_t cb, void *userdata);
+
+/** Change the profile of a sink. \since 0.9.15 */
+pa_operation* pa_context_set_sink_port_by_name(pa_context *c, const char*name, const char*port, pa_context_success_cb_t cb, void *userdata);
+
/** @} */
/** @{ \name Sources */
+/** Stores information about a specific port of a source. Please
+ * note that this structure can be extended as part of evolutionary
+ * API updates at any time in any new release. \since 0.9.16 */
+typedef struct pa_source_port_info {
+ const char *name; /**< Name of this port */
+ const char *description; /**< Description of this port */
+ uint32_t priority; /**< The higher this value is the more useful this port is as a default */
+} pa_source_port_info;
+
/** Stores information about sources. Please note that this structure
* can be extended as part of evolutionary API updates at any time in
* any new release. */
@@ -275,6 +302,9 @@ typedef struct pa_source_info {
pa_source_state_t state; /**< State \since 0.9.15 */
uint32_t n_volume_steps; /**< Number of volume steps for sources which do not support arbitrary volumes. \since 0.9.15 */
uint32_t card; /**< Card index, or PA_INVALID_INDEX. \since 0.9.15 */
+ uint32_t n_ports; /**< Number of entries in port array \since 0.9.16 */
+ pa_source_port_info** ports; /**< Array of available ports, or NULL. Array is terminated by an entry set to NULL. The number of entries is stored in n_ports \since 0.9.16 */
+ pa_source_port_info* active_port; /**< Pointer to active port in the array, or NULL \since 0.9.16 */
} pa_source_info;
/** Callback prototype for pa_context_get_source_info_by_name() and friends */
@@ -301,6 +331,12 @@ pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, i
/** Set the mute switch of a source device specified by its name */
pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata);
+/** Change the profile of a source. \since 0.9.16 */
+pa_operation* pa_context_set_source_port_by_index(pa_context *c, uint32_t idx, const char*port, pa_context_success_cb_t cb, void *userdata);
+
+/** Change the profile of a source. \since 0.9.15 */
+pa_operation* pa_context_set_source_port_by_name(pa_context *c, const char*name, const char*port, pa_context_success_cb_t cb, void *userdata);
+
/** @} */
/** @{ \name Server */
diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index 4c791dce..bc4dbd8a 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -206,6 +206,9 @@ PA_C_DECL_BEGIN
/** For devices: profile identifier for the profile this devices is in. e.g. "analog-stereo", "analog-surround-40", "iec958-stereo", ...*/
#define PA_PROP_DEVICE_PROFILE_NAME "device.profile.name"
+/** For devices: intended use. A comma seperated list of roles (see PA_PROP_MEDIA_ROLE) this device is particularly well suited for, due to latency, quality or form factor. \since 0.9.16 */
+#define PA_PROP_DEVICE_INTENDED_ROLES "device.intended_roles"
+
/** For devices: human readable one-line description of the profile this device is in. e.g. "Analog Stereo", ... */
#define PA_PROP_DEVICE_PROFILE_DESCRIPTION "device.profile.description"
diff --git a/src/pulse/version.h.in b/src/pulse/version.h.in
index 3143e98e..c2c1f20a 100644
--- a/src/pulse/version.h.in
+++ b/src/pulse/version.h.in
@@ -64,8 +64,8 @@ const char* pa_get_library_version(void);
* newer than the specified. \since 0.9.16 */
#define PA_CHECK_VERSION(major,minor,micro) \
((PA_MAJOR > (major)) || \
- (PA_MAJOR == (major) && CA_MINOR > (minor)) || \
- (PA_MAJOR == (major) && CA_MINOR == (minor) && CA_MICRO >= (micro)))
+ (PA_MAJOR == (major) && PA_MINOR > (minor)) || \
+ (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro)))
PA_C_DECL_END
diff --git a/src/pulse/volume.c b/src/pulse/volume.c
index 64688e0b..42cde5b9 100644
--- a/src/pulse/volume.c
+++ b/src/pulse/volume.c
@@ -27,8 +27,10 @@
#include <string.h>
#include <pulse/i18n.h>
+
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
+#include <pulsecore/sample-util.h>
#include "volume.h"
@@ -344,7 +346,7 @@ pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const
pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
- for (i = 0; i < a->channels && i < b->channels && i < PA_CHANNELS_MAX; i++)
+ for (i = 0; i < a->channels && i < b->channels; i++)
dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]);
dest->channels = (uint8_t) i;
@@ -352,6 +354,22 @@ pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const
return dest;
}
+pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
+ unsigned i;
+
+ pa_assert(dest);
+ pa_assert(a);
+
+ pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
+
+ for (i = 0; i < a->channels; i++)
+ dest->values[i] = pa_sw_volume_multiply(a->values[i], b);
+
+ dest->channels = (uint8_t) i;
+
+ return dest;
+}
+
pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
unsigned i;
@@ -362,7 +380,7 @@ pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa
pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
pa_return_val_if_fail(pa_cvolume_valid(b), NULL);
- for (i = 0; i < a->channels && i < b->channels && i < PA_CHANNELS_MAX; i++)
+ for (i = 0; i < a->channels && i < b->channels; i++)
dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]);
dest->channels = (uint8_t) i;
@@ -370,6 +388,22 @@ pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa
return dest;
}
+pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) {
+ unsigned i;
+
+ pa_assert(dest);
+ pa_assert(a);
+
+ pa_return_val_if_fail(pa_cvolume_valid(a), NULL);
+
+ for (i = 0; i < a->channels; i++)
+ dest->values[i] = pa_sw_volume_divide(a->values[i], b);
+
+ dest->channels = (uint8_t) i;
+
+ return dest;
+}
+
int pa_cvolume_valid(const pa_cvolume *v) {
unsigned c;
@@ -386,65 +420,27 @@ int pa_cvolume_valid(const pa_cvolume *v) {
}
static pa_bool_t on_left(pa_channel_position_t p) {
-
- return
- p == PA_CHANNEL_POSITION_FRONT_LEFT ||
- p == PA_CHANNEL_POSITION_REAR_LEFT ||
- p == PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER ||
- p == PA_CHANNEL_POSITION_SIDE_LEFT ||
- p == PA_CHANNEL_POSITION_TOP_FRONT_LEFT ||
- p == PA_CHANNEL_POSITION_TOP_REAR_LEFT;
+ return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT);
}
static pa_bool_t on_right(pa_channel_position_t p) {
-
- return
- p == PA_CHANNEL_POSITION_FRONT_RIGHT ||
- p == PA_CHANNEL_POSITION_REAR_RIGHT ||
- p == PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER ||
- p == PA_CHANNEL_POSITION_SIDE_RIGHT ||
- p == PA_CHANNEL_POSITION_TOP_FRONT_RIGHT ||
- p == PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
+ return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT);
}
static pa_bool_t on_center(pa_channel_position_t p) {
-
- return
- p == PA_CHANNEL_POSITION_FRONT_CENTER ||
- p == PA_CHANNEL_POSITION_REAR_CENTER ||
- p == PA_CHANNEL_POSITION_TOP_CENTER ||
- p == PA_CHANNEL_POSITION_TOP_FRONT_CENTER ||
- p == PA_CHANNEL_POSITION_TOP_REAR_CENTER;
+ return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER);
}
static pa_bool_t on_lfe(pa_channel_position_t p) {
-
- return
- p == PA_CHANNEL_POSITION_LFE;
+ return p == PA_CHANNEL_POSITION_LFE;
}
static pa_bool_t on_front(pa_channel_position_t p) {
-
- return
- p == PA_CHANNEL_POSITION_FRONT_LEFT ||
- p == PA_CHANNEL_POSITION_FRONT_RIGHT ||
- p == PA_CHANNEL_POSITION_FRONT_CENTER ||
- p == PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER ||
- p == PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER ||
- p == PA_CHANNEL_POSITION_TOP_FRONT_LEFT ||
- p == PA_CHANNEL_POSITION_TOP_FRONT_RIGHT ||
- p == PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
+ return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT);
}
static pa_bool_t on_rear(pa_channel_position_t p) {
-
- return
- p == PA_CHANNEL_POSITION_REAR_LEFT ||
- p == PA_CHANNEL_POSITION_REAR_RIGHT ||
- p == PA_CHANNEL_POSITION_REAR_CENTER ||
- p == PA_CHANNEL_POSITION_TOP_REAR_LEFT ||
- p == PA_CHANNEL_POSITION_TOP_REAR_RIGHT ||
- p == PA_CHANNEL_POSITION_TOP_REAR_CENTER;
+ return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR);
}
pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) {
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index c07fd99a..05b7ebb4 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -216,16 +216,26 @@ pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) PA_GCC_CONST;
* *dest. This is only valid for software volumes! */
pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b);
+/** Multiply a per-channel volume with a scalar volume and return the
+ * result in *dest. This is only valid for software volumes! \since
+ * 0.9.16 */
+pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b);
+
/** Divide two volume specifications, return the result. This uses
* PA_VOLUME_NORM as neutral element of division. This is only valid
* for software volumes! If a division by zero is tried the result
* will be 0. \since 0.9.13 */
pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) PA_GCC_CONST;
-/** Multiply to per-channel volumes and return the result in
+/** Divide two per-channel volumes and return the result in
* *dest. This is only valid for software volumes! \since 0.9.13 */
pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b);
+/** Divide a per-channel volume by a scalar volume and return the
+ * result in *dest. This is only valid for software volumes! \since
+ * 0.9.16 */
+pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b);
+
/** Convert a decibel value to a volume (amplitude, not power). This is only valid for software volumes! */
pa_volume_t pa_sw_volume_from_dB(double f) PA_GCC_CONST;
diff --git a/src/pulse/xmalloc.h b/src/pulse/xmalloc.h
index db20496f..f720d83f 100644
--- a/src/pulse/xmalloc.h
+++ b/src/pulse/xmalloc.h
@@ -88,9 +88,20 @@ static inline void* _pa_xnewdup_internal(const void *p, size_t n, size_t k) {
return pa_xmemdup(p, n*k);
}
-/** Same as pa_xnew() but set the memory to zero */
+/** Same as pa_xnew() but duplicate the specified data */
#define pa_xnewdup(type, p, n) ((type*) _pa_xnewdup_internal((p), (n), sizeof(type)))
+/** Internal helper for pa_xrenew() */
+static void* _pa_xrenew_internal(void *p, size_t n, size_t k) PA_GCC_MALLOC PA_GCC_ALLOC_SIZE2(2,3);
+
+static inline void* _pa_xrenew_internal(void *p, size_t n, size_t k) {
+ assert(n < INT_MAX/k);
+ return pa_xrealloc(p, n*k);
+}
+
+/** Reallocate n new structures of the specified type. */
+#define pa_xrenew(type, p, n) ((type*) _pa_xrenew_internal(p, (n), sizeof(type)))
+
PA_C_DECL_END
#endif