[PATCH 27/30] stream: Add pa_stream_set_initial_routing()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 src/map-file         |  1 +
 src/pulse/internal.h |  2 ++
 src/pulse/stream.c   | 50 ++++++++++++++++++++++++++++++++++++++++++++++----
 src/pulse/stream.h   | 30 +++++++++++++++++++++++++++---
 4 files changed, 76 insertions(+), 7 deletions(-)

diff --git a/src/map-file b/src/map-file
index 92d6c4b..3a39253 100644
--- a/src/map-file
+++ b/src/map-file
@@ -311,6 +311,7 @@ pa_stream_ref;
 pa_stream_set_buffer_attr;
 pa_stream_set_buffer_attr_callback;
 pa_stream_set_event_callback;
+pa_stream_set_initial_routing;
 pa_stream_set_latency_update_callback;
 pa_stream_set_monitor_stream;
 pa_stream_set_moved_callback;
diff --git a/src/pulse/internal.h b/src/pulse/internal.h
index c5084d5..350130d 100644
--- a/src/pulse/internal.h
+++ b/src/pulse/internal.h
@@ -165,6 +165,8 @@ struct pa_stream {
 
     uint32_t device_index;
     char *device_name;
+    char **initial_routing_nodes;
+    unsigned n_initial_routing_nodes;
 
     /* playback */
     pa_memblock *write_memblock;
diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index 7d77a0e..c67cee7 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -102,7 +102,7 @@ static pa_stream *pa_stream_new_with_proplist_internal(
     PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
     PA_CHECK_VALIDITY_RETURN_NULL(c, name || (p && pa_proplist_contains(p, PA_PROP_MEDIA_NAME)), PA_ERR_INVALID);
 
-    s = pa_xnew(pa_stream, 1);
+    s = pa_xnew0(pa_stream, 1);
     PA_REFCNT_INIT(s);
     s->context = c;
     s->mainloop = c->mainloop;
@@ -312,6 +312,10 @@ static void stream_free(pa_stream *s) {
     if (s->format)
         pa_format_info_free(s->format);
 
+    for (i = 0; i < s->n_initial_routing_nodes; i++)
+        pa_xfree(s->initial_routing_nodes[i]);
+
+    pa_xfree(s->initial_routing_nodes);
     pa_xfree(s->device_name);
     pa_xfree(s);
 }
@@ -949,6 +953,38 @@ static void invalidate_indexes(pa_stream *s, bool r, bool w) {
     request_auto_timing_update(s, true);
 }
 
+int pa_stream_set_initial_routing(pa_stream *s, const char * const *nodes, unsigned n_nodes) {
+    unsigned i;
+
+    pa_assert(s);
+    pa_assert(nodes || n_nodes == 0);
+
+    PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
+    PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
+    PA_CHECK_VALIDITY(s->context, s->direct_on_input == PA_INVALID_INDEX, PA_ERR_INVALID);
+    PA_CHECK_VALIDITY(s->context, s->context->version >= 30, PA_ERR_NOTSUPPORTED);
+
+    for (i = 0; i < s->n_initial_routing_nodes; i++)
+        pa_xfree(s->initial_routing_nodes[i]);
+
+    pa_xfree(s->initial_routing_nodes);
+    s->n_initial_routing_nodes = n_nodes;
+
+    if (n_nodes == 0) {
+        s->initial_routing_nodes = NULL;
+        return 0;
+    }
+
+    s->initial_routing_nodes = pa_xnew(char *, n_nodes);
+
+    for (i = 0; i < n_nodes; i++) {
+        pa_assert(nodes[i]);
+        s->initial_routing_nodes[i] = pa_xstrdup(nodes[i]);
+    }
+
+    return 0;
+}
+
 static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
     pa_stream *s = userdata;
 
@@ -1227,6 +1263,7 @@ static int create_stream(
     PA_CHECK_VALIDITY(s->context, !volume || s->n_formats || (pa_sample_spec_valid(&s->sample_spec) && volume->channels == s->sample_spec.channels), PA_ERR_INVALID);
     PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID);
     PA_CHECK_VALIDITY(s->context, (flags & (PA_STREAM_ADJUST_LATENCY|PA_STREAM_EARLY_REQUESTS)) != (PA_STREAM_ADJUST_LATENCY|PA_STREAM_EARLY_REQUESTS), PA_ERR_INVALID);
+    PA_CHECK_VALIDITY(s->context, !dev || s->n_initial_routing_nodes == 0, PA_ERR_INVALID);
 
     pa_stream_ref(s);
 
@@ -1258,7 +1295,7 @@ static int create_stream(
                 true);
     }
 
-    if (!dev)
+    if (!dev && s->direct_on_input == PA_INVALID_INDEX && s->n_initial_routing_nodes == 0)
         dev = s->direction == PA_STREAM_PLAYBACK ? s->context->conf->default_sink : s->context->conf->default_source;
 
     t = pa_tagstruct_command(
@@ -1373,8 +1410,12 @@ static int create_stream(
         pa_tagstruct_put_boolean(t, flags & (PA_STREAM_PASSTHROUGH));
     }
 
-    if (s->context->version >= 30)
-        pa_tagstruct_putu32(t, 0); /* n_initial_routing_nodes */
+    if (s->context->version >= 30) {
+        pa_tagstruct_putu32(t, s->n_initial_routing_nodes);
+
+        for (i = 0; i < s->n_initial_routing_nodes; i++)
+            pa_tagstruct_puts(t, s->initial_routing_nodes[i]);
+    }
 
     pa_pstream_send_tagstruct(s->context->pstream, t);
     pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL);
@@ -2887,6 +2928,7 @@ int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx) {
     PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
     PA_CHECK_VALIDITY(s->context, sink_input_idx != PA_INVALID_INDEX, PA_ERR_INVALID);
     PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
+    PA_CHECK_VALIDITY(s->context, s->n_initial_routing_nodes == 0, PA_ERR_INVALID);
     PA_CHECK_VALIDITY(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED);
 
     s->direct_on_input = sink_input_idx;
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index a6785ec..46b7984 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -418,6 +418,22 @@ int pa_stream_is_suspended(pa_stream *s);
  * not, and a negative value on error. \since 0.9.11 */
 int pa_stream_is_corked(pa_stream *s);
 
+/** Set the initial routing for the stream. \a nodes is an array of node names
+ * and \a n_nodes is the array size. This must be called before connecting the
+ * stream.
+ *
+ * It is strongly recommended to not use this function, unless some specific
+ * initial routing has been explicitly requested by the user. Leaving the
+ * routing unspecified allows the server to apply automatic routing logic.
+ *
+ * You may not use both this function and pa_stream_set_monitor_stream() on the
+ * same stream.
+ *
+ * Returns a negative error code on failure.
+ *
+ * \since 6.0 */
+int pa_stream_set_initial_routing(pa_stream *s, const char * const *nodes, unsigned n_nodes);
+
 /** Connect the stream to a sink. It is strongly recommended to pass
  * NULL in both \a dev and \a volume and not to set either
  * PA_STREAM_START_MUTED nor PA_STREAM_START_UNMUTED -- unless these
@@ -430,6 +446,8 @@ int pa_stream_is_corked(pa_stream *s);
  * reconfigure audio devices to make other sinks/sources or
  * capabilities available to be able to accept the stream.
  *
+ * If you use pa_stream_set_initial_routing(), then \a dev must be NULL.
+ *
  * Before 0.9.20 it was not defined whether the \a volume parameter was
  * interpreted relative to the sink's current volume or treated as
  * an absolute device volume. Since 0.9.20 it is an absolute volume when
@@ -444,7 +462,9 @@ int pa_stream_connect_playback(
         const pa_cvolume *volume      /**< Initial volume, or NULL for default */,
         pa_stream *sync_stream        /**< Synchronize this stream with the specified one, or NULL for a standalone stream */);
 
-/** Connect the stream to a source. */
+/** Connect the stream to a source.
+ *
+ * If you use pa_stream_set_initial_routing(), then \a dev must be NULL. */
 int pa_stream_connect_record(
         pa_stream *s                  /**< The stream to connect to a source */ ,
         const char *dev               /**< Name of the source to connect to, or NULL for default */,
@@ -781,8 +801,12 @@ pa_operation *pa_stream_proplist_remove(pa_stream *s, const char *const keys[],
 
 /** For record streams connected to a monitor source: monitor only a
  * very specific sink input of the sink. This function needs to be
- * called before pa_stream_connect_record() is called. \since
- * 0.9.11 */
+ * called before pa_stream_connect_record() is called.
+ *
+ * You may not use both this function and pa_stream_set_initial_routing() on
+ * the same stream.
+ *
+ * \since 0.9.11 */
 int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx);
 
 /** Return the sink input index previously set with
-- 
1.8.3.1



[Index of Archives]     [Linux Audio Users]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux