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

Chris Billington chrisjbillington at gmail.com
Tue Jan 5 15:21:08 PST 2016


Just to follow up with the use case behind this patch:

I'm working on streaming audio over a network using a null sink (capturing
its .monitor source), and it's very useful to have pulseaudio report to
apps the network latency as part of the latency of the sink. This keeps
audio and video in sync when watching video locally but using speakers of
another computer on the network.

The same issue was discussed here some time ago:
http://lists.freedesktop.org/archives/pulseaudio-discuss/2013-November/019135.html
and it didn't look too hard to patch, so I've had a go at doing so.

I haven't contributed to pulseaudio before so let me know if I've done
anything foolish.

Regards,

Chris

On Wed, Jan 6, 2016 at 2:36 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() to
> int64_t.
>
> Bumped protocol version number to 31.
> ---
>  PROTOCOL                        |  6 ++++
>  configure.ac                    |  2 +-
>  src/map-file                    |  2 ++
>  src/pulse/introspect.c          | 50 +++++++++++++++++++++++++++
>  src/pulse/introspect.h          |  6 ++++
>  src/pulsecore/cli-command.c     | 76
> ++++++++++++++++++++++++++++++++++++++++-
>  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               | 39 +++++++++++++++++++++
>  11 files changed, 263 insertions(+), 2 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/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..94a016c 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);
> @@ -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_atoi(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_atoi(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..f04bef4 100644
> --- a/src/utils/pactl.c
> +++ b/src/utils/pactl.c
> @@ -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"));
> @@ -2046,6 +2057,34 @@ int main(int argc, char *argv[]) {
>                  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_atoi(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_atoi(argv[optind + 2], &latency_offset) < 0) {
> +                pa_log(_("Could not parse latency offset"));
> +                goto quit;
> +            }
> +
>          } else if (pa_streq(argv[optind], "help")) {
>              help(bn);
>              ret = 0;
> --
> 2.5.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/pulseaudio-discuss/attachments/20160106/693edd34/attachment-0001.html>


More information about the pulseaudio-discuss mailing list