[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