[pulseaudio-discuss] [PATCH] Added set-(sink|source)-latency-offset commands to pactl and pacmd.

Chris Billington chrisjbillington at gmail.com
Mon Jan 11 22:05:47 PST 2016


Hi all,

Just to bump this thread, what are the odds of getting this patch included
in pulseaudio? It would be useful to many of the network audio streaming
services that use pulseaudio (specifically my one :p).

Cheers,

Chris

On Wed, Jan 6, 2016 at 11:51 AM, Chris Billington <
chrisjbillington at gmail.com> wrote:

> This required the addition of two commands to the protocol:
> PA_COMMAND_SET_SINK_LATENCY_OFFSET and
> PA_COMMAND_SET_SOURCE_LATENCY_OFFSET.
>
> Changed integer type for the offset in pa_cli_command_port_offset()
> in cli_command.c to int64_t.
> Changed integer type for latency_offset in pactl.c to int64_t.
>
> Bumped protocol version number to 31.
> ---
>  PROTOCOL                        |  6 ++++
>  configure.ac                    |  2 +-
>  man/pactl.1.xml.in              | 12 +++++++
>  man/pulse-cli-syntax.5.xml.in   | 10 ++++++
>  src/map-file                    |  2 ++
>  src/pulse/introspect.c          | 50 ++++++++++++++++++++++++++
>  src/pulse/introspect.h          |  6 ++++
>  src/pulsecore/cli-command.c     | 78
> +++++++++++++++++++++++++++++++++++++++--
>  src/pulsecore/native-common.h   |  4 +++
>  src/pulsecore/pdispatch.c       |  4 +++
>  src/pulsecore/protocol-native.c | 75
> +++++++++++++++++++++++++++++++++++++++
>  src/utils/pacmd.c               |  1 +
>  src/utils/pactl.c               | 43 +++++++++++++++++++++--
>  13 files changed, 288 insertions(+), 5 deletions(-)
>
> diff --git a/PROTOCOL b/PROTOCOL
> index 3c08fea..b6a5db7 100644
> --- a/PROTOCOL
> +++ b/PROTOCOL
> @@ -371,6 +371,12 @@ PA_COMMAND_DISABLE_SRBCHANNEL
>  Tells the client to stop listening on the additional SHM ringbuffer
> channel.
>  Acked by client by sending PA_COMMAND_DISABLE_SRBCHANNEL back.
>
> +## v31, implemented by >= 8.0
> +#
> +New opcodes:
> +    PA_COMMAND_SET_SINK_LATENCY_OFFSET
> +    PA_COMMAND_SET_SOURCE_LATENCY_OFFSET
> +
>  #### If you just changed the protocol, read this
>  ## module-tunnel depends on the sink/source/sink-input/source-input
> protocol
>  ## internals, so if you changed these, you might have broken
> module-tunnel.
> diff --git a/configure.ac b/configure.ac
> index ee1b437..e749024 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -40,7 +40,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, 30)
> +AC_SUBST(PA_PROTOCOL_VERSION, 31)
>
>  # The stable ABI for client applications, for the version info x:y:z
>  # always will hold y=z
> diff --git a/man/pactl.1.xml.in b/man/pactl.1.xml.in
> index c2064ca..530fb5d 100644
> --- a/man/pactl.1.xml.in
> +++ b/man/pactl.1.xml.in
> @@ -184,6 +184,18 @@ License along with PulseAudio; if not, see <
> http://www.gnu.org/licenses/>.
>      </option>
>
>      <option>
> +      <p><opt>set-sink-latency-offset</opt> <arg>SINK</arg>
> <arg>OFFSET</arg></p>
> +      <optdesc><p>Set a latency offset to a specified sink (identified by
> its symbolic name or numerical index).
> +      <arg>OFFSET</arg> is a number which represents the latency offset
> in microseconds</p></optdesc>
> +    </option>
> +
> +    <option>
> +      <p><opt>set-source-latency-offset</opt> <arg>SOURCE</arg>
> <arg>OFFSET</arg></p>
> +      <optdesc><p>Set a latency offset to a specified source (identified
> by its symbolic name or numerical index).
> +      <arg>OFFSET</arg> is a number which represents the latency offset
> in microseconds</p></optdesc>
> +    </option>
> +
> +    <option>
>        <p><opt>set-sink-volume</opt> <arg>SINK</arg> <arg>VOLUME [VOLUME
> ...]</arg></p>
>        <optdesc><p>Set the volume of the specified sink (identified by its
> symbolic name or numerical index).
>        <arg>VOLUME</arg> can be specified as an integer (e.g. 2000,
> 16384), a linear factor (e.g. 0.4, 1.100), a percentage
> diff --git a/man/pulse-cli-syntax.5.xml.in b/man/pulse-cli-syntax.5.xml.in
> index 0a0faba..1b976cc 100644
> --- a/man/pulse-cli-syntax.5.xml.in
> +++ b/man/pulse-cli-syntax.5.xml.in
> @@ -163,6 +163,16 @@ License along with PulseAudio; if not, see <
> http://www.gnu.org/licenses/>.
>      </option>
>
>      <option>
> +      <p><opt>set-sink-latency-offset</opt>
> <arg>sink-index|sink-name</arg> <arg>offset</arg> </p>
> +      <optdesc><p>Change the latency offset of a sink</p></optdesc>
> +    </option>
> +
> +    <option>
> +      <p><opt>set-source-latency-offset</opt>
> <arg>source-index|source-name</arg> <arg>offset</arg> </p>
> +      <optdesc><p>Change the latency offset of a source</p></optdesc>
> +    </option>
> +
> +    <option>
>        <p><opt>suspend-sink|suspend-source</opt> <arg>index|name</arg>
> <arg>boolean</arg></p>
>        <optdesc><p>Suspend (i.e. disconnect from the underlying hardware)
> a sink
>        (resp. source).</p></optdesc>
> diff --git a/src/map-file b/src/map-file
> index 93a62b8..7826fa4 100644
> --- a/src/map-file
> +++ b/src/map-file
> @@ -62,6 +62,8 @@ 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_set_sink_latency_offset;
> +pa_context_set_source_latency_offset;
>  pa_context_get_state;
>  pa_context_get_tile_size;
>  pa_context_is_local;
> diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
> index 510d784..7f8b0c0 100644
> --- a/src/pulse/introspect.c
> +++ b/src/pulse/introspect.c
> @@ -1926,6 +1926,56 @@ pa_operation*
> pa_context_set_port_latency_offset(pa_context *c, const char *card
>      return o;
>  }
>
> +pa_operation* pa_context_set_sink_latency_offset(pa_context *c, const
> char *sink_name, int64_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, sink_name && *sink_name,
> PA_ERR_INVALID);
> +    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 31,
> PA_ERR_NOTSUPPORTED);
> +
> +    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
> +
> +    t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_LATENCY_OFFSET, &tag);
> +    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
> +    pa_tagstruct_puts(t, sink_name);
> +    pa_tagstruct_puts64(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;
> +}
> +
> +pa_operation* pa_context_set_source_latency_offset(pa_context *c, const
> char *source_name, int64_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, source_name && *source_name,
> PA_ERR_INVALID);
> +    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 31,
> PA_ERR_NOTSUPPORTED);
> +
> +    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
> +
> +    t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_LATENCY_OFFSET,
> &tag);
> +    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
> +    pa_tagstruct_puts(t, source_name);
> +    pa_tagstruct_puts64(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 43389b7..bd23467 100644
> --- a/src/pulse/introspect.h
> +++ b/src/pulse/introspect.h
> @@ -550,6 +550,12 @@ pa_operation*
> pa_context_set_card_profile_by_name(pa_context *c, const char*name
>  /** 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, int64_t offset,
> pa_context_success_cb_t cb, void *userdata);
>
> +/** Set the latency offset of a sink. \since 8.0 */
> +pa_operation* pa_context_set_sink_latency_offset(pa_context *c, const
> char *sink_name, int64_t offset, pa_context_success_cb_t cb, void
> *userdata);
> +
> +/** Set the latency offset of a source. \since 8.0 */
> +pa_operation* pa_context_set_source_latency_offset(pa_context *c, const
> char *source_name, int64_t offset, pa_context_success_cb_t cb, void
> *userdata);
> +
>  /** @} */
>
>  /** @{ \name Sink Inputs */
> diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
> index 9a73605..6e694db 100644
> --- a/src/pulsecore/cli-command.c
> +++ b/src/pulsecore/cli-command.c
> @@ -134,6 +134,8 @@ static int pa_cli_command_card_profile(pa_core *c,
> pa_tokenizer *t, pa_strbuf *b
>  static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t,
> pa_strbuf *buf, bool *fail);
>  static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t,
> pa_strbuf *buf, bool *fail);
>  static int pa_cli_command_port_offset(pa_core *c, pa_tokenizer *t,
> pa_strbuf *buf, bool *fail);
> +static int pa_cli_command_sink_offset(pa_core *c, pa_tokenizer *t,
> pa_strbuf *buf, bool *fail);
> +static int pa_cli_command_source_offset(pa_core *c, pa_tokenizer *t,
> pa_strbuf *buf, bool *fail);
>  static int pa_cli_command_dump_volumes(pa_core *c, pa_tokenizer *t,
> pa_strbuf *buf, bool *fail);
>
>  /* A method table for all available commands */
> @@ -168,6 +170,8 @@ static const struct command commands[] = {
>      { "set-sink-port",           pa_cli_command_sink_port,
> "Change the port of a sink (args: index|name, port-name)", 3},
>      { "set-source-port",         pa_cli_command_source_port,
> "Change the port of a source (args: index|name, port-name)", 3},
>      { "set-port-latency-offset", pa_cli_command_port_offset,
> "Change the latency of a port (args: card-index|card-name, port-name,
> latency-offset)", 4},
> +    { "set-sink-latency-offset", pa_cli_command_sink_offset,
> "Change the latency of a sink (args: sink-index|sink-name,
> latency-offset)", 3},
> +    { "set-source-latency-offset", pa_cli_command_source_offset,
> "Change the latency of a source (args: source-index|source-name,
> latency-offset)", 3},
>      { "suspend-sink",            pa_cli_command_suspend_sink,
>  "Suspend sink (args: index|name, bool)", 3},
>      { "suspend-source",          pa_cli_command_suspend_source,
>  "Suspend source (args: index|name, bool)", 3},
>      { "suspend",                 pa_cli_command_suspend,
> "Suspend all sinks and all sources (args: bool)", 2},
> @@ -1735,7 +1739,7 @@ static int pa_cli_command_port_offset(pa_core *c,
> pa_tokenizer *t, pa_strbuf *bu
>      const char *n, *p, *l;
>      pa_device_port *port;
>      pa_card *card;
> -    int32_t offset;
> +    int64_t offset;
>
>      pa_core_assert_ref(c);
>      pa_assert(t);
> @@ -1757,7 +1761,7 @@ static int pa_cli_command_port_offset(pa_core *c,
> pa_tokenizer *t, pa_strbuf *bu
>          return -1;
>      }
>
> -    if (pa_atoi(l, &offset) < 0) {
> +    if (pa_atol(l, &offset) < 0) {
>          pa_strbuf_puts(buf, "Failed to parse the latency offset.\n");
>          return -1;
>      }
> @@ -1777,6 +1781,76 @@ static int pa_cli_command_port_offset(pa_core *c,
> pa_tokenizer *t, pa_strbuf *bu
>      return 0;
>  }
>
> +static int pa_cli_command_sink_offset(pa_core *c, pa_tokenizer *t,
> pa_strbuf *buf, bool *fail) {
> +    const char *n, *l;
> +    pa_sink *sink;
> +    int64_t offset;
> +
> +    pa_core_assert_ref(c);
> +    pa_assert(t);
> +    pa_assert(buf);
> +    pa_assert(fail);
> +
> +    if (!(n = pa_tokenizer_get(t, 1))) {
> +           pa_strbuf_puts(buf, "You need to specify a sink either by its
> name or its index.\n");
> +           return -1;
> +    }
> +
> +    if (!(l = pa_tokenizer_get(t, 2))) {
> +        pa_strbuf_puts(buf, "You need to specify a latency offset.\n");
> +        return -1;
> +    }
> +
> +    if (pa_atol(l, &offset) < 0) {
> +        pa_strbuf_puts(buf, "Failed to parse the latency offset.\n");
> +        return -1;
> +    }
> +
> +    if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
> +        pa_strbuf_puts(buf, "No sink found by this name or index.\n");
> +        return -1;
> +    }
> +
> +    pa_sink_set_latency_offset(sink, offset);
> +
> +    return 0;
> +}
> +
> +static int pa_cli_command_source_offset(pa_core *c, pa_tokenizer *t,
> pa_strbuf *buf, bool *fail) {
> +    const char *n, *l;
> +    pa_source *source;
> +    int64_t offset;
> +
> +    pa_core_assert_ref(c);
> +    pa_assert(t);
> +    pa_assert(buf);
> +    pa_assert(fail);
> +
> +    if (!(n = pa_tokenizer_get(t, 1))) {
> +           pa_strbuf_puts(buf, "You need to specify a source either by
> its name or its index.\n");
> +           return -1;
> +    }
> +
> +    if (!(l = pa_tokenizer_get(t, 2))) {
> +        pa_strbuf_puts(buf, "You need to specify a latency offset.\n");
> +        return -1;
> +    }
> +
> +    if (pa_atol(l, &offset) < 0) {
> +        pa_strbuf_puts(buf, "Failed to parse the latency offset.\n");
> +        return -1;
> +    }
> +
> +    if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
> +        pa_strbuf_puts(buf, "No source found by this name or index.\n");
> +        return -1;
> +    }
> +
> +    pa_source_set_latency_offset(source, offset);
> +
> +    return 0;
> +}
> +
>  static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf
> *buf, bool *fail) {
>      pa_module *m;
>      pa_sink *sink;
> diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h
> index dc62895..b32a235 100644
> --- a/src/pulsecore/native-common.h
> +++ b/src/pulsecore/native-common.h
> @@ -179,6 +179,10 @@ enum {
>      PA_COMMAND_ENABLE_SRBCHANNEL,
>      PA_COMMAND_DISABLE_SRBCHANNEL,
>
> +    /* Supported since protocol v31 (8.0) */
> +    PA_COMMAND_SET_SINK_LATENCY_OFFSET,
> +    PA_COMMAND_SET_SOURCE_LATENCY_OFFSET,
> +
>      PA_COMMAND_MAX
>  };
>
> diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c
> index f136875..5b58a3f 100644
> --- a/src/pulsecore/pdispatch.c
> +++ b/src/pulsecore/pdispatch.c
> @@ -195,6 +195,10 @@ static const char *command_names[PA_COMMAND_MAX] = {
>      /* BOTH DIRECTIONS */
>      [PA_COMMAND_ENABLE_SRBCHANNEL] = "ENABLE_SRBCHANNEL",
>      [PA_COMMAND_DISABLE_SRBCHANNEL] = "DISABLE_SRBCHANNEL",
> +
> +    /* Supported since protocol v31 (8.0) */
> +    [PA_COMMAND_SET_SINK_LATENCY_OFFSET] = "SET_SINK_LATENCY_OFFSET",
> +    [PA_COMMAND_SET_SOURCE_LATENCY_OFFSET] = "SET_SOURCE_LATENCY_OFFSET",
>  };
>
>  #endif
> diff --git a/src/pulsecore/protocol-native.c
> b/src/pulsecore/protocol-native.c
> index 145db04..43372ac 100644
> --- a/src/pulsecore/protocol-native.c
> +++ b/src/pulsecore/protocol-native.c
> @@ -293,6 +293,8 @@ static void command_extension(pa_pdispatch *pd,
> uint32_t command, uint32_t tag,
>  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 void command_set_sink_latency_offset(pa_pdispatch *pd, uint32_t
> command, uint32_t tag, pa_tagstruct *t, void *userdata);
> +static void command_set_source_latency_offset(pa_pdispatch *pd, uint32_t
> command, uint32_t tag, pa_tagstruct *t, void *userdata);
>  static void command_enable_srbchannel(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] = {
> @@ -397,6 +399,9 @@ static const pa_pdispatch_cb_t
> command_table[PA_COMMAND_MAX] = {
>
>      [PA_COMMAND_SET_PORT_LATENCY_OFFSET] =
> command_set_port_latency_offset,
>
> +    [PA_COMMAND_SET_SINK_LATENCY_OFFSET] =
> command_set_sink_latency_offset,
> +    [PA_COMMAND_SET_SOURCE_LATENCY_OFFSET] =
> command_set_source_latency_offset,
> +
>      [PA_COMMAND_ENABLE_SRBCHANNEL] = command_enable_srbchannel,
>
>      [PA_COMMAND_EXTENSION] = command_extension
> @@ -4887,6 +4892,76 @@ static void
> command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command,
>      pa_pstream_send_simple_ack(c->pstream, tag);
>  }
>
> +static void command_set_sink_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 *sink_name;
> +    uint32_t idx = PA_INVALID_INDEX;
> +    int64_t offset;
> +    pa_sink *sink = NULL;
> +
> +    pa_native_connection_assert_ref(c);
> +    pa_assert(t);
> +
> +    if (pa_tagstruct_getu32(t, &idx) < 0 ||
> +        pa_tagstruct_gets(t, &sink_name) < 0 ||
> +        pa_tagstruct_gets64(t, &offset) < 0 ||
> +        !pa_tagstruct_eof(t)) {
> +        protocol_error(c);
> +        return;
> +    }
> +
> +    CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
> +    CHECK_VALIDITY(c->pstream, !sink_name ||
> pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag,
> PA_ERR_INVALID);
> +    CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (sink_name !=
> NULL), tag, PA_ERR_INVALID);
> +    CHECK_VALIDITY(c->pstream, sink_name, tag, PA_ERR_INVALID);
> +
> +    if (idx != PA_INVALID_INDEX)
> +        sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
> +    else
> +        sink = pa_namereg_get(c->protocol->core, sink_name,
> PA_NAMEREG_SINK);
> +
> +    CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
> +
> +    pa_sink_set_latency_offset(sink, offset);
> +
> +    pa_pstream_send_simple_ack(c->pstream, tag);
> +}
> +
> +static void command_set_source_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 *source_name;
> +    uint32_t idx = PA_INVALID_INDEX;
> +    int64_t offset;
> +    pa_source *source = NULL;
> +
> +    pa_native_connection_assert_ref(c);
> +    pa_assert(t);
> +
> +    if (pa_tagstruct_getu32(t, &idx) < 0 ||
> +        pa_tagstruct_gets(t, &source_name) < 0 ||
> +        pa_tagstruct_gets64(t, &offset) < 0 ||
> +        !pa_tagstruct_eof(t)) {
> +        protocol_error(c);
> +        return;
> +    }
> +
> +    CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
> +    CHECK_VALIDITY(c->pstream, !source_name ||
> pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag,
> PA_ERR_INVALID);
> +    CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (source_name
> != NULL), tag, PA_ERR_INVALID);
> +    CHECK_VALIDITY(c->pstream, source_name, tag, PA_ERR_INVALID);
> +
> +    if (idx != PA_INVALID_INDEX)
> +        source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
> +    else
> +        source = pa_namereg_get(c->protocol->core, source_name,
> PA_NAMEREG_SOURCE);
> +
> +    CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
> +
> +    pa_source_set_latency_offset(source, offset);
> +
> +    pa_pstream_send_simple_ack(c->pstream, tag);
> +}
> +
>  /*** pstream callbacks ***/
>
>  static void pstream_packet_callback(pa_pstream *p, pa_packet *packet,
> const pa_cmsg_ancil_data *ancil_data, void *userdata) {
> diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c
> index 616573c..e0ea919 100644
> --- a/src/utils/pacmd.c
> +++ b/src/utils/pacmd.c
> @@ -72,6 +72,7 @@ static void help(const char *argv0) {
>      printf("%s %s %s\n", argv0, "set-card-profile", _("CARD PROFILE"));
>      printf("%s %s %s\n", argv0, "set-(sink|source)-port", _("NAME|#N
> PORT"));
>      printf("%s %s %s\n", argv0, "set-port-latency-offset",
> _("CARD-NAME|CARD-#N PORT OFFSET"));
> +    printf("%s %s %s\n", argv0, "set-sink-(sink|source)-latency-offset",
> _("NAME|#N OFFSET"));
>      printf("%s %s %s\n", argv0, "set-log-target", _("TARGET"));
>      printf("%s %s %s\n", argv0, "set-log-level", _("NUMERIC-LEVEL"));
>      printf("%s %s %s\n", argv0, "set-log-meta", _("1|0"));
> diff --git a/src/utils/pactl.c b/src/utils/pactl.c
> index e9bf005..b627971 100644
> --- a/src/utils/pactl.c
> +++ b/src/utils/pactl.c
> @@ -65,7 +65,7 @@ static uint32_t
>
>  static bool short_list_format = false;
>  static uint32_t module_index;
> -static int32_t latency_offset;
> +static int64_t latency_offset;
>  static bool suspend;
>  static pa_cvolume volume;
>  static enum volume_flags {
> @@ -130,6 +130,8 @@ static enum {
>      SET_SOURCE_OUTPUT_MUTE,
>      SET_SINK_FORMATS,
>      SET_PORT_LATENCY_OFFSET,
> +    SET_SINK_LATENCY_OFFSET,
> +    SET_SOURCE_LATENCY_OFFSET,
>      SUBSCRIBE
>  } action = NONE;
>
> @@ -1404,6 +1406,14 @@ static void context_state_callback(pa_context *c,
> void *userdata) {
>                      o = pa_context_set_port_latency_offset(c, card_name,
> port_name, latency_offset, simple_callback, NULL);
>                      break;
>
> +                case SET_SINK_LATENCY_OFFSET:
> +                    o = pa_context_set_sink_latency_offset(c, sink_name,
> latency_offset, simple_callback, NULL);
> +                    break;
> +
> +                case SET_SOURCE_LATENCY_OFFSET:
> +                    o = pa_context_set_source_latency_offset(c,
> source_name, latency_offset, simple_callback, NULL);
> +                    break;
> +
>                  case SUBSCRIBE:
>                      pa_context_set_subscribe_callback(c,
> context_subscribe_callback, NULL);
>
> @@ -1580,6 +1590,7 @@ static void help(const char *argv0) {
>      printf("%s %s %s %s\n", argv0, _("[options]"),
> "set-(sink-input|source-output)-mute", _("#N 1|0|toggle"));
>      printf("%s %s %s %s\n", argv0, _("[options]"), "set-sink-formats",
> _("#N FORMATS"));
>      printf("%s %s %s %s\n", argv0, _("[options]"),
> "set-port-latency-offset", _("CARD-NAME|CARD-#N PORT OFFSET"));
> +    printf("%s %s %s %s\n", argv0, _("[options]"),
> "set-(sink|source)-latency-offset", _("NAME|#N OFFSET"));
>      printf("%s %s %s\n",    argv0, _("[options]"), "subscribe");
>      printf(_("\nThe special names @DEFAULT_SINK@, @DEFAULT_SOURCE@ and
> @DEFAULT_MONITOR@\n"
>               "can be used to specify the default sink, source and
> monitor.\n"));
> @@ -2041,7 +2052,35 @@ int main(int argc, char *argv[]) {
>
>              card_name = pa_xstrdup(argv[optind+1]);
>              port_name = pa_xstrdup(argv[optind+2]);
> -            if (pa_atoi(argv[optind + 3], &latency_offset) < 0) {
> +            if (pa_atol(argv[optind + 3], &latency_offset) < 0) {
> +                pa_log(_("Could not parse latency offset"));
> +                goto quit;
> +            }
> +
> +        } else if (pa_streq(argv[optind], "set-sink-latency-offset")) {
> +            action = SET_SINK_LATENCY_OFFSET;
> +
> +            if (argc != optind+3) {
> +                pa_log(_("You have to specify a sink name/index and a
> latency offset"));
> +                goto quit;
> +            }
> +
> +            sink_name = pa_xstrdup(argv[optind+1]);
> +            if (pa_atol(argv[optind + 2], &latency_offset) < 0) {
> +                pa_log(_("Could not parse latency offset"));
> +                goto quit;
> +            }
> +
> +        } else if (pa_streq(argv[optind], "set-source-latency-offset")) {
> +            action = SET_SOURCE_LATENCY_OFFSET;
> +
> +            if (argc != optind+3) {
> +                pa_log(_("You have to specify a source name/index and a
> latency offset"));
> +                goto quit;
> +            }
> +
> +            source_name = pa_xstrdup(argv[optind+1]);
> +            if (pa_atol(argv[optind + 2], &latency_offset) < 0) {
>                  pa_log(_("Could not parse latency offset"));
>                  goto quit;
>              }
> --
> 2.5.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/pulseaudio-discuss/attachments/20160112/93d24b3c/attachment-0001.html>


More information about the pulseaudio-discuss mailing list