summaryrefslogtreecommitdiffstats
path: root/src/pulse
diff options
context:
space:
mode:
authorColin Guthrie <colin@mageia.org>2011-05-17 22:31:10 +0100
committerColin Guthrie <colin@mageia.org>2011-06-22 22:45:27 +0100
commitdffc4d18d3a9f608f8b316f1e7057d13978ef44f (patch)
tree2967eec64a3884b1b2ae5b7e5f59fafc92097ebf /src/pulse
parentfdf3a0881445560e962924a02319fc5cd2506231 (diff)
capture: Implement per-stream volume control for capture streams.
This piggy backs onto the previous changes for protocol 22 and thus does not bump the version. This and the previous commits should be seen as mostly atomic. Apologies for any bisecting issues this causes (although I would expect these to be minimal)
Diffstat (limited to 'src/pulse')
-rw-r--r--src/pulse/introspect.c61
-rw-r--r--src/pulse/introspect.h15
-rw-r--r--src/pulse/stream.c38
3 files changed, 93 insertions, 21 deletions
diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
index a781c14f..d6ad0f50 100644
--- a/src/pulse/introspect.c
+++ b/src/pulse/introspect.c
@@ -1164,7 +1164,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;
- pa_bool_t corked = FALSE;
+ pa_bool_t mute = FALSE, corked = FALSE, has_volume = FALSE, volume_writable = TRUE;
pa_zero(i);
i.proplist = pa_proplist_new();
@@ -1181,14 +1181,21 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c
pa_tagstruct_gets(t, &i.resample_method) < 0 ||
pa_tagstruct_gets(t, &i.driver) < 0 ||
(o->context->version >= 13 && pa_tagstruct_get_proplist(t, i.proplist) < 0) ||
- (o->context->version >= 19 && pa_tagstruct_get_boolean(t, &corked) < 0)) {
+ (o->context->version >= 19 && pa_tagstruct_get_boolean(t, &corked) < 0) ||
+ (o->context->version >= 22 && (pa_tagstruct_get_cvolume(t, &i.volume) < 0 ||
+ pa_tagstruct_get_boolean(t, &mute) < 0 ||
+ pa_tagstruct_get_boolean(t, &has_volume) < 0 ||
+ pa_tagstruct_get_boolean(t, &volume_writable) < 0))) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
pa_proplist_free(i.proplist);
goto finish;
}
+ i.mute = (int) mute;
i.corked = (int) corked;
+ i.has_volume = (int) has_volume;
+ i.volume_writable = (int) volume_writable;
if (o->callback) {
pa_source_output_info_cb_t cb = (pa_source_output_info_cb_t) o->callback;
@@ -1487,6 +1494,56 @@ pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name
return o;
}
+pa_operation* pa_context_set_source_output_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, 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_assert(volume);
+
+ 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 >= 22, PA_ERR_NOTSUPPORTED);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID);
+
+ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+ t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME, &tag);
+ pa_tagstruct_putu32(t, idx);
+ pa_tagstruct_put_cvolume(t, volume);
+ 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_output_mute(pa_context *c, uint32_t idx, int mute, 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 >= 22, PA_ERR_NOTSUPPORTED);
+
+ o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+ t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_OUTPUT_MUTE, &tag);
+ pa_tagstruct_putu32(t, idx);
+ pa_tagstruct_put_boolean(t, mute);
+ 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;
+}
+
/** Sample Cache **/
static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index 65f12d12..84a12b62 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -164,9 +164,8 @@
*
* If an application desires to modify the volume of just a single stream
* (commonly one of its own streams), this can be done by setting the volume
- * of its associated sink input, using pa_context_set_sink_input_volume().
- *
- * There is no support for modifying the volume of source outputs.
+ * of its associated sink input or source output, using
+ * pa_context_set_sink_input_volume() or pa_context_set_source_output_volume()
*
* It is also possible to remove sink inputs and source outputs, terminating
* the streams associated with them:
@@ -558,6 +557,10 @@ typedef struct pa_source_output_info {
const char *driver; /**< Driver name */
pa_proplist *proplist; /**< Property list \since 0.9.11 */
int corked; /**< Stream corked \since 1.0 */
+ pa_cvolume volume; /**< The volume of this source output \since 1.0 */
+ int mute; /**< Stream muted \since 1.0 */
+ int has_volume; /**< Stream has volume. If not set, then the meaning of this struct's volume member is unspecified. \since 1.0 */
+ int volume_writable; /**< The volume can be set. If not set, the volume can still change even though clients can't control the volume. \since 1.0 */
} pa_source_output_info;
/** Callback prototype for pa_context_get_source_output_info() and friends*/
@@ -575,6 +578,12 @@ pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx,
/** Move the specified source output to a different source. \since 0.9.5 */
pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata);
+/** Set the volume of a source output stream \since 1.0 */
+pa_operation* pa_context_set_source_output_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
+
+/** Set the mute switch of a source output stream \since 1.0 */
+pa_operation* pa_context_set_source_output_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata);
+
/** Kill a source output. */
pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata);
diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index 32936848..d60b864b 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -1149,7 +1149,8 @@ static int create_stream(
pa_tagstruct *t;
uint32_t tag;
- pa_bool_t volume_set = FALSE;
+ pa_bool_t volume_set = !!volume;
+ pa_cvolume cv;
uint32_t i;
pa_assert(s);
@@ -1246,9 +1247,18 @@ static int create_stream(
PA_TAG_BOOLEAN, s->corked,
PA_TAG_INVALID);
- if (s->direction == PA_STREAM_PLAYBACK) {
- pa_cvolume cv;
+ if (!volume) {
+ if (pa_sample_spec_valid(&s->sample_spec))
+ volume = pa_cvolume_reset(&cv, s->sample_spec.channels);
+ else {
+ /* This is not really relevant, since no volume was set, and
+ * the real number of channels is embedded in the format_info
+ * structure */
+ volume = pa_cvolume_reset(&cv, PA_CHANNELS_MAX);
+ }
+ }
+ if (s->direction == PA_STREAM_PLAYBACK) {
pa_tagstruct_put(
t,
PA_TAG_U32, s->buffer_attr.tlength,
@@ -1257,19 +1267,6 @@ static int create_stream(
PA_TAG_U32, s->syncid,
PA_TAG_INVALID);
- volume_set = !!volume;
-
- if (!volume) {
- if (pa_sample_spec_valid(&s->sample_spec))
- volume = pa_cvolume_reset(&cv, s->sample_spec.channels);
- else {
- /* This is not really relevant, since no volume was set, and
- * the real number of channels is embedded in the format_info
- * structure */
- volume = pa_cvolume_reset(&cv, PA_CHANNELS_MAX);
- }
- }
-
pa_tagstruct_put_cvolume(t, volume);
} else
pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
@@ -1335,6 +1332,15 @@ static int create_stream(
pa_tagstruct_put_format_info(t, s->req_formats[i]);
}
+ if (s->context->version >= 22 && s->direction == PA_STREAM_RECORD) {
+ pa_tagstruct_put_cvolume(t, volume);
+ pa_tagstruct_put_boolean(t, flags & PA_STREAM_START_MUTED);
+ pa_tagstruct_put_boolean(t, volume_set);
+ pa_tagstruct_put_boolean(t, flags & (PA_STREAM_START_MUTED|PA_STREAM_START_UNMUTED));
+ pa_tagstruct_put_boolean(t, flags & PA_STREAM_RELATIVE_VOLUME);
+ pa_tagstruct_put_boolean(t, flags & (PA_STREAM_PASSTHROUGH));
+ }
+
pa_pstream_send_tagstruct(s->context->pstream, t);
pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL);