[pulseaudio-discuss] [PATCH 1/6] stream: Add a pa_stream_set_volume() API
arun at accosted.net
arun at accosted.net
Mon Dec 28 19:33:40 PST 2015
From: Arun Raghavan <git at arunraghavan.net>
This makes it easier for clients to deal with the volume of a stream
(they currently have to use pa_context_set_sink_input_volume(), which is
a bit clunky given everything else is based around the pa_stream_* API).
In addition, this will also provide us a bit of context with respect to
whether the client is controlling the stream volume from a "stream"
perspective (mixer within an app) or a "global" perspective (a mixer
app).
---
src/map-file | 1 +
src/pulse/internal.h | 3 +++
src/pulse/stream.c | 64 ++++++++++++++++++++++++++++++++++++++++++++--------
src/pulse/stream.h | 9 ++++++++
4 files changed, 68 insertions(+), 9 deletions(-)
diff --git a/src/map-file b/src/map-file
index 93a62b8..93f7178 100644
--- a/src/map-file
+++ b/src/map-file
@@ -326,6 +326,7 @@ pa_stream_set_started_callback;
pa_stream_set_state_callback;
pa_stream_set_suspended_callback;
pa_stream_set_underflow_callback;
+pa_stream_set_volume;
pa_stream_set_write_callback;
pa_stream_trigger;
pa_stream_unref;
diff --git a/src/pulse/internal.h b/src/pulse/internal.h
index eefd181..74b2b32 100644
--- a/src/pulse/internal.h
+++ b/src/pulse/internal.h
@@ -151,6 +151,9 @@ struct pa_stream {
pa_proplist *proplist;
+ pa_cvolume volume;
+ bool volume_set;
+
bool channel_valid:1;
bool suspended:1;
bool corked:1;
diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index 6fea996..0f5dd73 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -196,6 +196,9 @@ static pa_stream *pa_stream_new_with_proplist_internal(
s->smoother = NULL;
+ pa_cvolume_init(&s->volume);
+ s->volume_set = false;
+
/* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */
PA_LLIST_PREPEND(pa_stream, c->streams, s);
pa_stream_ref(s);
@@ -1191,8 +1194,6 @@ static int create_stream(
pa_tagstruct *t;
uint32_t tag;
- bool volume_set = !!volume;
- pa_cvolume cv;
uint32_t i;
pa_assert(s);
@@ -1286,14 +1287,19 @@ static int create_stream(
PA_TAG_BOOLEAN, s->corked,
PA_TAG_INVALID);
- if (!volume) {
+ if (volume) {
+ s->volume = *volume;
+ s->volume_set = true;
+ }
+
+ if (!s->volume_set) {
if (pa_sample_spec_valid(&s->sample_spec))
- volume = pa_cvolume_reset(&cv, s->sample_spec.channels);
+ pa_cvolume_reset(&s->volume, 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_cvolume_reset(&s->volume, PA_CHANNELS_MAX);
}
}
@@ -1306,7 +1312,7 @@ static int create_stream(
PA_TAG_U32, s->syncid,
PA_TAG_INVALID);
- pa_tagstruct_put_cvolume(t, volume);
+ pa_tagstruct_put_cvolume(t, &s->volume);
} else
pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
@@ -1343,7 +1349,7 @@ static int create_stream(
if (s->context->version >= 14) {
if (s->direction == PA_STREAM_PLAYBACK)
- pa_tagstruct_put_boolean(t, volume_set);
+ pa_tagstruct_put_boolean(t, s->volume_set);
pa_tagstruct_put_boolean(t, flags & PA_STREAM_EARLY_REQUESTS);
}
@@ -1372,9 +1378,9 @@ static int create_stream(
}
if (s->context->version >= 22 && s->direction == PA_STREAM_RECORD) {
- pa_tagstruct_put_cvolume(t, volume);
+ pa_tagstruct_put_cvolume(t, &s->volume);
pa_tagstruct_put_boolean(t, flags & PA_STREAM_START_MUTED);
- pa_tagstruct_put_boolean(t, volume_set);
+ pa_tagstruct_put_boolean(t, s->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));
@@ -2922,3 +2928,43 @@ uint32_t pa_stream_get_monitor_stream(pa_stream *s) {
return s->direct_on_input;
}
+
+int pa_stream_set_volume(pa_stream *s, pa_cvolume *v, pa_stream_success_cb_t cb, void *userdata) {
+ pa_operation *o;
+ pa_tagstruct *t;
+ uint32_t tag;
+
+ pa_assert(s);
+ pa_assert(v);
+ pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
+ PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
+ PA_CHECK_VALIDITY(s->context, s->state != PA_STREAM_FAILED && s->state != PA_STREAM_TERMINATED, PA_ERR_BADSTATE);
+ PA_CHECK_VALIDITY(s->context, userdata == NULL || cb != NULL, PA_ERR_INVALID);
+ PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_INVALID); /* TODO: do we want to support this? */
+ PA_CHECK_VALIDITY(s->context, pa_cvolume_valid(v), PA_ERR_INVALID);
+ PA_CHECK_VALIDITY(s->context, pa_cvolume_compatible(v, &s->sample_spec), PA_ERR_INVALID);
+
+ if (s->state == PA_STREAM_UNCONNECTED) {
+ /* Just cache the value till the stream is being connected */
+ s->volume = *v;
+ s->volume_set = true;
+
+ if (cb)
+ cb(s, 1, userdata);
+
+ return 0;
+ }
+
+ o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
+
+ t = pa_tagstruct_command(s->context,
+ s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_SET_SINK_INPUT_VOLUME : PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME,
+ &tag);
+ pa_tagstruct_putu32(t, s->stream_index);
+ pa_tagstruct_put_cvolume(t, v);
+ pa_pstream_send_tagstruct(s->context->pstream, t);
+ pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+ return 0;
+}
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index 70fa415..cc74629 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -819,6 +819,15 @@ int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx);
* \since 0.9.11 */
uint32_t pa_stream_get_monitor_stream(pa_stream *s);
+/** Set the volume on the given stream. The operation is asynchronous and a
+ * callback may optionally be provided to be invoked when the volume has been
+ * set.
+ *
+ * Returns 0 on success, negative error value on failure.
+ *
+ * \since 9.0 */
+int pa_stream_set_volume(pa_stream *s, pa_cvolume *v, pa_stream_success_cb_t cb, void *userdata);
+
PA_C_DECL_END
#endif
--
2.5.0
More information about the pulseaudio-discuss
mailing list