[pulseaudio-discuss] [PATCH 4/5] introspect: Add functions to handle the latency offset.

poljar (Damir Jelic) poljarinho at gmail.com
Fri Jun 22 11:55:56 PDT 2012


From: "poljar (Damir Jelic)" <poljarinho at gmail.com>

This includes updating the native protocol and the client API.
A new command was added to allow setting the latency offset.

Also all the relevant list commands (sinks, sources, cards) now show the
latency offset if there are ports available.

Update protocol to 27.
---
 PROTOCOL                        | 13 ++++++++++
 configure.ac                    |  2 +-
 src/map-file                    |  1 +
 src/modules/module-tunnel.c     |  5 ++++
 src/pulse/introspect.c          | 53 +++++++++++++++++++++++++++++++++++++++--
 src/pulse/introspect.h          |  6 +++++
 src/pulsecore/native-common.h   |  3 +++
 src/pulsecore/protocol-native.c | 52 ++++++++++++++++++++++++++++++++++++++++
 8 files changed, 132 insertions(+), 3 deletions(-)

diff --git a/PROTOCOL b/PROTOCOL
index acd53ba..203d5f5 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -321,6 +321,19 @@ PA_COMMAND_GET_CARD_INFO_LIST), the following is added:
 
 Profile names must match earlier sent profile names for the same card.
 
+## v27, implemented by >= 3.0
+
+New opcodes:
+    PA_COMMAND_SET_PORT_LATENCY_OFFSET
+
+New field in all commands that send/receive port introspection data
+(PA_COMMAND_GET_(SOURCE|SINK)_OUTPUT_INFO,
+PA_COMMAND_GET_(SOURCE|SINK)_OUTPUT_INFO_LIST
+PA_COMMAND_GET_CARD_INFO(_LIST)):
+
+    pa_usec_t latency_offset
+
+The field is added once for every port.
 
 #### If you just changed the protocol, read this
 ## module-tunnel depends on the sink/source/sink-input/source-input protocol
diff --git a/configure.ac b/configure.ac
index f5f9b76..62cc5f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,7 +36,7 @@ AC_SUBST(PA_MINOR, pa_minor)
 AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
 
 AC_SUBST(PA_API_VERSION, 12)
-AC_SUBST(PA_PROTOCOL_VERSION, 26)
+AC_SUBST(PA_PROTOCOL_VERSION, 27)
 
 # The stable ABI for client applications, for the version info x:y:z
 # always will hold y=z
diff --git a/src/map-file b/src/map-file
index 69cf25b..fe34b97 100644
--- a/src/map-file
+++ b/src/map-file
@@ -59,6 +59,7 @@ pa_context_get_source_info_by_name;
 pa_context_get_source_info_list;
 pa_context_get_source_output_info;
 pa_context_get_source_output_info_list;
+pa_context_set_port_latency_offset;
 pa_context_get_state;
 pa_context_get_tile_size;
 pa_context_is_local;
diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c
index e336d15..a7cf9ef 100644
--- a/src/modules/module-tunnel.c
+++ b/src/modules/module-tunnel.c
@@ -1009,6 +1009,7 @@ static int read_ports(struct userdata *u, pa_tagstruct *t)
 
         for (uint32_t j = 0; j < n_ports; j++) {
             uint32_t priority;
+            pa_usec_t latency_offset;
 
             if (pa_tagstruct_gets(t, &s) < 0 || /* name */
                 pa_tagstruct_gets(t, &s) < 0 || /* description */
@@ -1021,6 +1022,10 @@ static int read_ports(struct userdata *u, pa_tagstruct *t)
                 pa_log("Parse failure");
                 return -PA_ERR_PROTOCOL;
             }
+            if (u->version >= 27 && pa_tagstruct_get_usec(t, &latency_offset) < 0) {
+                pa_log("Parse failure");
+                return -PA_ERR_PROTOCOL;
+            }
         }
 
         if (pa_tagstruct_gets(t, &s) < 0) { /* active port */
diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
index 38a9d1c..18c1768 100644
--- a/src/pulse/introspect.c
+++ b/src/pulse/introspect.c
@@ -219,6 +219,14 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u
                             i.ports[0][j].available = av;
                         }
 
+                        i.ports[0][j].latency_offset = 0;
+                        if (o->context->version >= 27) {
+                            pa_usec_t offset;
+                            if (pa_tagstruct_get_usec(t, &offset) < 0)
+                                goto fail;
+                            i.ports[0][j].latency_offset = offset;
+                        }
+
                         i.ports[j] = &i.ports[0][j];
                     }
 
@@ -492,6 +500,14 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
                             i.ports[0][j].available = av;
                         }
 
+                        i.ports[0][j].latency_offset = 0;
+                        if (o->context->version >= 27) {
+                            pa_usec_t offset;
+                            if (pa_tagstruct_get_usec(t, &offset) < 0)
+                                goto fail;
+                            i.ports[0][j].latency_offset = offset;
+                        }
+
                         i.ports[j] = &i.ports[0][j];
                     }
 
@@ -787,8 +803,9 @@ static void card_info_free(pa_card_info* i)
     }
 }
 
-static int fill_card_port_info(pa_tagstruct* t, pa_card_info* i)
+static int fill_card_port_info(void *userdata, pa_tagstruct* t, pa_card_info* i)
 {
+    pa_operation *o = userdata;
     uint32_t j, k, l;
 
     if (pa_tagstruct_getu32(t, &i->n_ports) < 0)
@@ -849,6 +866,11 @@ static int fill_card_port_info(pa_tagstruct* t, pa_card_info* i)
                     return -PA_ERR_PROTOCOL;
             }
         }
+        if (o->context->version >= 27)
+            if (pa_tagstruct_get_usec(t, &port->latency_offset) < 0)
+                return -PA_ERR_PROTOCOL;
+        else
+            port->latency_offset = 0;
     }
 
     return 0;
@@ -931,7 +953,7 @@ static void context_get_card_info_callback(pa_pdispatch *pd, uint32_t command, u
             }
 
             if (o->context->version >= 26) {
-                if (fill_card_port_info(t, &i) < 0) {
+                if (fill_card_port_info(userdata, t, &i) < 0) {
                     pa_context_fail(o->context, PA_ERR_PROTOCOL);
                     card_info_free(&i);
                     goto finish;
@@ -1868,6 +1890,33 @@ pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_s
     return command_kill(c, PA_COMMAND_UNLOAD_MODULE, idx, cb, userdata);
 }
 
+pa_operation* pa_context_set_port_latency_offset(pa_context *c, const char *card_name, const char *port_name, pa_usec_t offset, 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, card_name && *card_name, PA_ERR_INVALID);
+    PA_CHECK_VALIDITY_RETURN_NULL(c, port_name && *port_name, PA_ERR_INVALID);
+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 27, PA_ERR_NOTSUPPORTED);
+
+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+    t = pa_tagstruct_command(c, PA_COMMAND_SET_PORT_LATENCY_OFFSET, &tag);
+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
+    pa_tagstruct_puts(t, card_name);
+    pa_tagstruct_puts(t, port_name);
+    pa_tagstruct_put_usec(t, offset);
+    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;
+}
+
 /*** Autoload stuff ***/
 
 PA_WARN_REFERENCE(pa_context_get_autoload_info_by_name, "Module auto-loading no longer supported.");
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index 0072f5d..3973d7a 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -203,6 +203,7 @@ typedef struct pa_sink_port_info {
     const char *description;            /**< Description of this port */
     uint32_t priority;                  /**< The higher this value is, the more useful this port is as a default. */
     int available;                      /**< A flags (see #pa_port_available), indicating availability status of this port. \since 2.0 */
+    pa_usec_t latency_offset;           /**< Latency offset of the port that gets added to the sink if the port is active. \since 3.0 */
 } pa_sink_port_info;
 
 /** Stores information about sinks. Please note that this structure
@@ -283,6 +284,7 @@ typedef struct pa_source_port_info {
     const char *description;            /**< Description of this port */
     uint32_t priority;                  /**< The higher this value is, the more useful this port is as a default. */
     int available;                      /**< A flags (see #pa_port_available), indicating availability status of this port. \since 2.0 */
+    pa_usec_t latency_offset;           /**< Latency offset of the port that gets added to the source if the port is active. \since 3.0 */
 } pa_source_port_info;
 
 /** Stores information about sources. Please note that this structure
@@ -466,6 +468,7 @@ typedef struct pa_card_port_info {
     uint32_t n_profiles;                /**< Number of entries in profile array */
     pa_card_profile_info** profiles;    /**< Array of pointers to available profiles, or NULL. Array is terminated by an entry set to NULL. */
     pa_proplist *proplist;              /**< Property list */
+    pa_usec_t latency_offset;           /**< Latency offset of the port that gets added to the sink/source if the port is active. \since 3.0 */
 } pa_card_port_info;
 
 /** Stores information about cards. Please note that this structure
@@ -502,6 +505,9 @@ pa_operation* pa_context_set_card_profile_by_index(pa_context *c, uint32_t idx,
 /** Change the profile of a card. \since 0.9.15 */
 pa_operation* pa_context_set_card_profile_by_name(pa_context *c, const char*name, const char*profile, pa_context_success_cb_t cb, void *userdata);
 
+/** Set the latency offset of a port. \since 3.0 */
+pa_operation* pa_context_set_port_latency_offset(pa_context *c, const char *card_name, const char *port_name, pa_usec_t offset, pa_context_success_cb_t cb, void *userdata);
+
 /** @} */
 
 /** @{ \name Sink Inputs */
diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h
index 8fde023..dad82e0 100644
--- a/src/pulsecore/native-common.h
+++ b/src/pulsecore/native-common.h
@@ -173,6 +173,9 @@ enum {
     PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME,
     PA_COMMAND_SET_SOURCE_OUTPUT_MUTE,
 
+    /* Supported since protocol v27 (3.0) */
+    PA_COMMAND_SET_PORT_LATENCY_OFFSET,
+
     PA_COMMAND_MAX
 };
 
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index c24254a..716724d 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -292,6 +292,7 @@ static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t
 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 
 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
     [PA_COMMAND_ERROR] = NULL,
@@ -393,6 +394,8 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
     [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
     [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
 
+    [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = command_set_port_latency_offset,
+
     [PA_COMMAND_EXTENSION] = command_extension
 };
 
@@ -3126,6 +3129,9 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin
                 pa_tagstruct_putu32(t, p->priority);
                 if (c->version >= 24)
                     pa_tagstruct_putu32(t, p->available);
+
+                if (c->version >= 27)
+                    pa_tagstruct_put_usec(t, p->latency_offset);
             }
         }
 
@@ -3199,6 +3205,8 @@ static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s
                 pa_tagstruct_putu32(t, p->priority);
                 if (c->version >= 24)
                     pa_tagstruct_putu32(t, p->available);
+                if (c->version >= 27)
+                    pa_tagstruct_put_usec(t, p->latency_offset);
             }
         }
 
@@ -3283,6 +3291,9 @@ static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_car
                     pa_tagstruct_puts(t, p->name);
             } else
                 pa_tagstruct_putu32(t, 0);
+
+            if (c->version >= 27)
+                pa_tagstruct_put_usec(t, port->latency_offset);
         }
 
         pa_proplist_free(proplist);
@@ -4734,6 +4745,47 @@ static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command,
     pa_pstream_send_simple_ack(c->pstream, tag);
 }
 
+static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+    pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
+    const char *port_name, *card_name;
+    uint32_t idx = PA_INVALID_INDEX;
+    pa_usec_t offset;
+    pa_card *card = NULL;
+    pa_device_port *port = NULL;
+
+    pa_native_connection_assert_ref(c);
+    pa_assert(t);
+
+    if (pa_tagstruct_getu32(t, &idx) < 0 ||
+        pa_tagstruct_gets(t, &card_name) < 0 ||
+        pa_tagstruct_gets(t, &port_name) < 0 ||
+        pa_tagstruct_get_usec(t, &offset) < 0 ||
+        !pa_tagstruct_eof(t)) {
+        protocol_error(c);
+    }
+
+    CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
+    CHECK_VALIDITY(c->pstream, !card_name || pa_namereg_is_valid_name(card_name), tag, PA_ERR_INVALID);
+    CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || card_name, tag, PA_ERR_INVALID);
+    CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !card_name, tag, PA_ERR_INVALID);
+    CHECK_VALIDITY(c->pstream, !card_name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
+    CHECK_VALIDITY(c->pstream, port_name, tag, PA_ERR_INVALID);
+
+    if (idx != PA_INVALID_INDEX)
+        card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
+    else
+        card = pa_namereg_get(c->protocol->core, card_name, PA_NAMEREG_CARD);
+
+    CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
+
+    port = pa_hashmap_get(card->ports, port_name);
+    CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_NOENTITY);
+
+    pa_device_port_set_latency_offset(port, offset);
+
+    pa_pstream_send_simple_ack(c->pstream, tag);
+}
+
 /*** pstream callbacks ***/
 
 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
-- 
1.7.11



More information about the pulseaudio-discuss mailing list