Hello, Yeah I was adding this "start ramp muted" in quite late stage and was not paying attention... I was also little bit confused about this version "jungle" :) Anyway the idea was only to add it to playback side. I guess the problem will go away if I remove setting the flag later in the recording side? if (s->context->version >= 22 && s->direction == PA_STREAM_RECORD) { pa_tagstruct_put_cvolume(t, volume); pa_tagstruct_put_boolean(t, flags & PA_STREAM_START_MUTED); pa_tagstruct_put_boolean(t, 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)); } br, Jaska Quoting "Flavio Ceolin" <flavio.ceolin at profusion.mobi>: > Hi Jaska, > > Jaska Uimonen <jaska.uimonen at helsinki.fi> writes: > >> From: Jaska Uimonen <jaska.uimonen at helsinki.fi> >> >> --- >> src/map-file | 3 + >> src/pulse/introspect.c | 83 ++++++++++++++++++++++++++++++++++++ >> src/pulse/introspect.h | 9 ++++ >> src/pulse/stream.c | 5 ++- >> src/pulsecore/native-common.h | 3 + >> src/pulsecore/pdispatch.c | 2 + >> src/pulsecore/protocol-native.c | 88 >> ++++++++++++++++++++++++++++++++++++++- >> 7 files changed, 190 insertions(+), 3 deletions(-) >> >> diff --git a/src/map-file b/src/map-file >> index 69cf25b..2e2791a 100644 >> --- a/src/map-file >> +++ b/src/map-file >> @@ -91,12 +91,15 @@ pa_context_set_event_callback; >> pa_context_set_name; >> pa_context_set_sink_input_mute; >> pa_context_set_sink_input_volume; >> +pa_context_set_sink_input_volume_ramp; >> pa_context_set_sink_mute_by_index; >> pa_context_set_sink_mute_by_name; >> pa_context_set_sink_port_by_index; >> pa_context_set_sink_port_by_name; >> pa_context_set_sink_volume_by_index; >> pa_context_set_sink_volume_by_name; >> +pa_context_set_sink_volume_ramp_by_index; >> +pa_context_set_sink_volume_ramp_by_name; >> pa_context_set_source_output_mute; >> pa_context_set_source_output_volume; >> pa_context_set_source_mute_by_index; >> diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c >> index 38a9d1c..6d13d8f 100644 >> --- a/src/pulse/introspect.c >> +++ b/src/pulse/introspect.c >> @@ -1412,6 +1412,62 @@ pa_operation* >> pa_context_set_sink_volume_by_name(pa_context *c, const char *name >> return o; >> } >> >> +pa_operation* pa_context_set_sink_volume_ramp_by_index(pa_context >> *c, uint32_t idx, const pa_cvolume *volume, uint32_t time, int >> type, 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_assert(volume); >> + >> + 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, pa_cvolume_valid(volume), >> PA_ERR_INVALID); >> + >> + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); >> + >> + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME_RAMP, &tag); >> + pa_tagstruct_putu32(t, idx); >> + pa_tagstruct_puts(t, NULL); >> + pa_tagstruct_put_cvolume(t, volume); >> + pa_tagstruct_putu32(t, time); >> + pa_tagstruct_putu8(t, type); >> + 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_sink_volume_ramp_by_name(pa_context >> *c, const char *name, const pa_cvolume *volume, uint32_t time, int >> type, 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_assert(name); >> + pa_assert(volume); >> + >> + 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, pa_cvolume_valid(volume), >> PA_ERR_INVALID); >> + PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); >> + >> + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); >> + >> + t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME_RAMP, &tag); >> + pa_tagstruct_putu32(t, PA_INVALID_INDEX); >> + pa_tagstruct_puts(t, name); >> + pa_tagstruct_put_cvolume(t, volume); >> + pa_tagstruct_putu32(t, time); >> + pa_tagstruct_putu8(t, type); >> + 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_sink_mute_by_index(pa_context *c, >> uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { >> pa_operation *o; >> pa_tagstruct *t; >> @@ -1509,6 +1565,33 @@ pa_operation* >> pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mu >> return o; >> } >> >> +pa_operation* pa_context_set_sink_input_volume_ramp(pa_context *c, >> uint32_t idx, const pa_cvolume *volume, uint32_t time, int type, >> 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_assert(volume); >> + >> + 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, pa_cvolume_valid(volume), >> PA_ERR_INVALID); >> + >> + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); >> + >> + t = pa_tagstruct_command(c, >> PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP, &tag); >> + pa_tagstruct_putu32(t, idx); >> + pa_tagstruct_puts(t, NULL); >> + pa_tagstruct_put_cvolume(t, volume); >> + pa_tagstruct_putu32(t, time); >> + pa_tagstruct_putu8(t, type); >> + 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_volume_by_index(pa_context *c, >> uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, >> void *userdata) { >> pa_operation *o; >> pa_tagstruct *t; >> diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h >> index 0072f5d..3098141 100644 >> --- a/src/pulse/introspect.h >> +++ b/src/pulse/introspect.h >> @@ -259,6 +259,12 @@ pa_operation* >> pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int >> /** Set the mute switch of a sink device specified by its name */ >> pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, >> const char *name, int mute, pa_context_success_cb_t cb, void >> *userdata); >> >> +/** Set the volume ramp of a sink device specified by its index */ >> +pa_operation* pa_context_set_sink_volume_ramp_by_index(pa_context >> *c, uint32_t idx, const pa_cvolume *volume, uint32_t time, int >> type, pa_context_success_cb_t cb, void *userdata); >> + >> +/** Set the volume ramp of a sink device specified by its name */ >> +pa_operation* pa_context_set_sink_volume_ramp_by_name(pa_context >> *c, const char *name, const pa_cvolume *volume, uint32_t time, int >> type, pa_context_success_cb_t cb, void *userdata); >> + >> /** Suspend/Resume a sink. \since 0.9.7 */ >> pa_operation* pa_context_suspend_sink_by_name(pa_context *c, const >> char *sink_name, int suspend, pa_context_success_cb_t cb, void* >> userdata); >> >> @@ -554,6 +560,9 @@ pa_operation* >> pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mu >> /** Kill a sink input. */ >> pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t >> idx, pa_context_success_cb_t cb, void *userdata); >> >> +/** Set the volume ramp of a sink input specified by its index */ >> +pa_operation* pa_context_set_sink_input_volume_ramp(pa_context *c, >> uint32_t idx, const pa_cvolume *volume, uint32_t time, int type, >> pa_context_success_cb_t cb, void *userdata); >> + >> /** @} */ >> >> /** @{ \name Source Outputs */ >> diff --git a/src/pulse/stream.c b/src/pulse/stream.c >> index 39338c1..1bfe108 100644 >> --- a/src/pulse/stream.c >> +++ b/src/pulse/stream.c >> @@ -1202,7 +1202,8 @@ static int create_stream( >> PA_STREAM_START_UNMUTED| >> PA_STREAM_FAIL_ON_SUSPEND| >> PA_STREAM_RELATIVE_VOLUME| >> - >> PA_STREAM_PASSTHROUGH)), PA_ERR_INVALID); >> + PA_STREAM_PASSTHROUGH| >> + >> PA_STREAM_START_RAMP_MUTED)), PA_ERR_INVALID); >> >> >> PA_CHECK_VALIDITY(s->context, s->context->version >= 12 || >> !(flags & PA_STREAM_VARIABLE_RATE), PA_ERR_NOTSUPPORTED); >> @@ -1350,6 +1351,8 @@ static int create_stream( >> if ((s->context->version >= 21 && s->direction == PA_STREAM_PLAYBACK) >> || s->context->version >= 22) { >> >> + pa_tagstruct_put_boolean(t, flags & (PA_STREAM_START_RAMP_MUTED)); >> + > > Are you sure about to add the ramp for the source too ? > If yes, you need to get the property in the function > protocol-native.c:command_create_record_stream, otherwise it'll fail > when getting the format. > If not, just checking the stream direction before adding the flag. > > I found this problem, when I tried to run the pavucontrol and pulseaudio > shown a message of protocol error. > >> pa_tagstruct_putu8(t, s->n_formats); >> for (i = 0; i < s->n_formats; i++) >> pa_tagstruct_put_format_info(t, s->req_formats[i]); >> diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h >> index 8fde023..8dda0e5 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, >> >> + PA_COMMAND_SET_SINK_VOLUME_RAMP, >> + PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP, >> + >> PA_COMMAND_MAX >> }; >> >> diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c >> index 9a9ef4e..e94cde4 100644 >> --- a/src/pulsecore/pdispatch.c >> +++ b/src/pulsecore/pdispatch.c >> @@ -190,6 +190,8 @@ static const char *command_names[PA_COMMAND_MAX] = { >> [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = "SET_SOURCE_OUTPUT_VOLUME", >> [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = "SET_SOURCE_OUTPUT_MUTE", >> >> + [PA_COMMAND_SET_SINK_VOLUME_RAMP] = "SET_SINK_VOLUME_RAMP", >> + [PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP] = "SET_SINK_INPUT_VOLUME_RAMP", >> }; >> >> #endif >> diff --git a/src/pulsecore/protocol-native.c >> b/src/pulsecore/protocol-native.c >> index c24254a..5164c4c 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_volume_ramp(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,9 @@ 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_SINK_VOLUME_RAMP] = command_set_volume_ramp, >> + [PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP] = command_set_volume_ramp, >> + >> [PA_COMMAND_EXTENSION] = command_extension >> }; >> >> @@ -1954,7 +1958,8 @@ static void >> command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u >> muted_set = FALSE, >> fail_on_suspend = FALSE, >> relative_volume = FALSE, >> - passthrough = FALSE; >> + passthrough = FALSE, >> + ramp_muted = FALSE; >> >> pa_sink_input_flags_t flags = 0; >> pa_proplist *p = NULL; >> @@ -2066,6 +2071,11 @@ static void >> command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u >> >> if (c->version >= 21) { >> >> + if (pa_tagstruct_get_boolean(t, &ramp_muted) < 0 ) { >> + protocol_error(c); >> + goto finish; >> + } >> + >> if (pa_tagstruct_getu8(t, &n_formats) < 0) { >> protocol_error(c); >> goto finish; >> @@ -2082,6 +2092,7 @@ static void >> command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u >> } >> pa_idxset_put(formats, format, NULL); >> } >> + >> } >> >> if (n_formats == 0) { >> @@ -2125,7 +2136,8 @@ static void >> command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u >> (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) | >> (dont_inhibit_auto_suspend ? >> PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) | >> (fail_on_suspend ? >> PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : >> 0) | >> - (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0); >> + (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0) | >> + (ramp_muted ? PA_SINK_INPUT_START_RAMP_MUTED : 0); >> >> /* Only since protocol version 15 there's a separate muted_set >> * flag. For older versions we synthesize it here */ >> @@ -3769,6 +3781,78 @@ static void command_set_volume( >> pa_pstream_send_simple_ack(c->pstream, tag); >> } >> >> +static void command_set_volume_ramp( >> + pa_pdispatch *pd, >> + uint32_t command, >> + uint32_t tag, >> + pa_tagstruct *t, >> + void *userdata) { >> + >> + pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); >> + uint32_t idx; >> + pa_cvolume volume; >> + uint32_t time; >> + uint8_t type; >> + pa_sink *sink = NULL; >> + pa_sink_input *si = NULL; >> + const char *name = NULL; >> + const char *client_name; >> + >> + pa_native_connection_assert_ref(c); >> + pa_assert(t); >> + >> + if (pa_tagstruct_getu32(t, &idx) < 0 || >> + (command == PA_COMMAND_SET_SINK_VOLUME_RAMP && >> pa_tagstruct_gets(t, &name) < 0) || >> + (command == PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP && >> pa_tagstruct_gets(t, &name) < 0) || >> + pa_tagstruct_get_cvolume(t, &volume) || >> + pa_tagstruct_getu32(t, &time) < 0 || >> + pa_tagstruct_getu8(t, &type) < 0 || >> + !pa_tagstruct_eof(t)) { >> + protocol_error(c); >> + return; >> + } >> + >> + CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); >> + CHECK_VALIDITY(c->pstream, !name || >> pa_namereg_is_valid_name_or_wildcard(name, command == >> PA_COMMAND_SET_SINK_VOLUME ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), >> tag, PA_ERR_INVALID); >> + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, >> tag, PA_ERR_INVALID); >> + CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, >> tag, PA_ERR_INVALID); >> + CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, >> tag, PA_ERR_INVALID); >> + CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, >> PA_ERR_INVALID); >> + >> + switch (command) { >> + >> + case PA_COMMAND_SET_SINK_VOLUME_RAMP: >> + if (idx != PA_INVALID_INDEX) >> + sink = >> pa_idxset_get_by_index(c->protocol->core->sinks, idx); >> + else >> + sink = pa_namereg_get(c->protocol->core, name, >> PA_NAMEREG_SINK); >> + break; >> + >> + case PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP: >> + si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); >> + break; >> + >> + default: >> + pa_assert_not_reached(); >> + } >> + >> + CHECK_VALIDITY(c->pstream, sink || si, tag, PA_ERR_NOENTITY); >> + >> + client_name = pa_strnull(pa_proplist_gets(c->client->proplist, >> PA_PROP_APPLICATION_PROCESS_BINARY)); >> + >> + if (sink) { >> + CHECK_VALIDITY(c->pstream, volume.channels == 1 || >> pa_cvolume_compatible(&volume, &sink->sample_spec), tag, >> PA_ERR_INVALID); >> + pa_log_debug("Client %s changes volume ramp of sink %s.", >> client_name, sink->name); >> + pa_sink_set_volume_ramp(sink, &volume, time, type, TRUE, TRUE); >> + } else if (si) { >> + CHECK_VALIDITY(c->pstream, volume.channels == 1 || >> pa_cvolume_compatible(&volume, &si->sample_spec), tag, >> PA_ERR_INVALID); >> + pa_log_debug("Client %s changes volume ramp of sink input >> %s.", client_name, pa_strnull(pa_proplist_gets(si->proplist, >> PA_PROP_MEDIA_NAME))); >> + pa_sink_input_set_volume_ramp(si, &volume, time, type, TRUE, TRUE); >> + } >> + >> + pa_pstream_send_simple_ack(c->pstream, tag); >> +} >> + >> static void command_set_mute( >> pa_pdispatch *pd, >> uint32_t command, > > Best Regards, > Flavio Ceolin > _______________________________________________ > pulseaudio-discuss mailing list > pulseaudio-discuss at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss >