summaryrefslogtreecommitdiffstats
path: root/src/pulsecore/protocol-native.c
diff options
context:
space:
mode:
authorColin Guthrie <colin@mageia.org>2011-05-17 22:31:10 +0100
committerColin Guthrie <colin@mageia.org>2011-06-22 22:45:27 +0100
commitdffc4d18d3a9f608f8b316f1e7057d13978ef44f (patch)
tree2967eec64a3884b1b2ae5b7e5f59fafc92097ebf /src/pulsecore/protocol-native.c
parentfdf3a0881445560e962924a02319fc5cd2506231 (diff)
capture: Implement per-stream volume control for capture streams.
This piggy backs onto the previous changes for protocol 22 and thus does not bump the version. This and the previous commits should be seen as mostly atomic. Apologies for any bisecting issues this causes (although I would expect these to be minimal)
Diffstat (limited to 'src/pulsecore/protocol-native.c')
-rw-r--r--src/pulsecore/protocol-native.c78
1 files changed, 74 insertions, 4 deletions
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 3574ca98..d90b470a 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -338,10 +338,12 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
[PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
[PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
+ [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = command_set_volume,
[PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
[PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
[PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
+ [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = command_set_mute,
[PA_COMMAND_SUSPEND_SINK] = command_suspend,
[PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
@@ -631,10 +633,14 @@ static record_stream* record_stream_new(
pa_channel_map *map,
pa_idxset *formats,
pa_buffer_attr *attr,
+ pa_cvolume *volume,
+ pa_bool_t muted,
+ pa_bool_t muted_set,
pa_source_output_flags_t flags,
pa_proplist *p,
pa_bool_t adjust_latency,
pa_bool_t early_requests,
+ pa_bool_t relative_volume,
pa_bool_t peak_detect,
pa_sink_input *direct_on_input,
int *ret) {
@@ -663,6 +669,15 @@ static record_stream* record_stream_new(
if (formats)
pa_source_output_new_data_set_formats(&data, formats);
data.direct_on_input = direct_on_input;
+ if (volume) {
+ pa_source_output_new_data_set_volume(&data, volume);
+ data.volume_is_absolute = !relative_volume;
+ data.save_volume = TRUE;
+ }
+ if (muted_set) {
+ pa_source_output_new_data_set_muted(&data, muted);
+ data.save_muted = TRUE;
+ }
if (peak_detect)
data.resample_method = PA_RESAMPLER_PEAKS;
data.flags = flags;
@@ -2215,6 +2230,7 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
pa_channel_map map;
pa_tagstruct *reply;
pa_source *source = NULL;
+ pa_cvolume volume;
pa_bool_t
corked = FALSE,
no_remap = FALSE,
@@ -2224,11 +2240,15 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
fix_channels = FALSE,
no_move = FALSE,
variable_rate = FALSE,
+ muted = FALSE,
adjust_latency = FALSE,
peak_detect = FALSE,
early_requests = FALSE,
dont_inhibit_auto_suspend = FALSE,
+ volume_set = TRUE,
+ muted_set = FALSE,
fail_on_suspend = FALSE,
+ relative_volume = FALSE,
passthrough = FALSE;
pa_source_output_flags_t flags = 0;
@@ -2333,10 +2353,24 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
}
pa_idxset_put(formats, format, NULL);
}
+
+ if (pa_tagstruct_get_cvolume(t, &volume) < 0 ||
+ pa_tagstruct_get_boolean(t, &muted) < 0 ||
+ pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
+ pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
+ pa_tagstruct_get_boolean(t, &relative_volume) < 0 ||
+ pa_tagstruct_get_boolean(t, &passthrough) < 0) {
+
+ protocol_error(c);
+ goto finish;
+ }
+
+ CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
}
if (n_formats == 0) {
CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
+ CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish);
CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
} else {
PA_IDXSET_FOREACH(format, formats, i) {
@@ -2386,7 +2420,7 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
(fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0) |
(passthrough ? PA_SOURCE_OUTPUT_PASSTHROUGH : 0);
- s = record_stream_new(c, source, &ss, &map, formats, &attr, flags, p, adjust_latency, early_requests, peak_detect, direct_on_input, &ret);
+ s = record_stream_new(c, source, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, p, adjust_latency, early_requests, relative_volume, peak_detect, direct_on_input, &ret);
CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
@@ -3249,12 +3283,20 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t,
static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
pa_sample_spec fixed_ss;
pa_usec_t source_latency;
+ pa_cvolume v;
+ pa_bool_t has_volume = FALSE;
pa_assert(t);
pa_source_output_assert_ref(s);
fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
+ has_volume = pa_source_output_is_volume_readable(s);
+ if (has_volume)
+ pa_source_output_get_volume(s, &v, TRUE);
+ else
+ pa_cvolume_reset(&v, fixed_ss.channels);
+
pa_tagstruct_putu32(t, s->index);
pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
@@ -3270,6 +3312,12 @@ static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *
pa_tagstruct_put_proplist(t, s->proplist);
if (c->version >= 19)
pa_tagstruct_put_boolean(t, (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_CORKED));
+ if (c->version >= 22) {
+ pa_tagstruct_put_cvolume(t, &v);
+ pa_tagstruct_put_boolean(t, pa_source_output_get_mute(s));
+ pa_tagstruct_put_boolean(t, has_volume);
+ pa_tagstruct_put_boolean(t, s->volume_writable);
+ }
}
static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
@@ -3564,6 +3612,7 @@ static void command_set_volume(
pa_sink *sink = NULL;
pa_source *source = NULL;
pa_sink_input *si = NULL;
+ pa_source_output *so = NULL;
const char *name = NULL;
const char *client_name;
@@ -3606,11 +3655,15 @@ static void command_set_volume(
si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
break;
+ case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME:
+ so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
+ break;
+
default:
pa_assert_not_reached();
}
- CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
+ CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
@@ -3623,7 +3676,7 @@ static void command_set_volume(
CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
- pa_source_set_volume(source, &volume, TRUE);
+ pa_source_set_volume(source, &volume, TRUE, TRUE);
} else if (si) {
CHECK_VALIDITY(c->pstream, si->volume_writable, tag, PA_ERR_BADSTATE);
CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
@@ -3632,6 +3685,13 @@ static void command_set_volume(
client_name,
pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
+ } else if (so) {
+ CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &so->sample_spec), tag, PA_ERR_INVALID);
+
+ pa_log_debug("Client %s changes volume of source output %s.",
+ client_name,
+ pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
+ pa_source_output_set_volume(so, &volume, TRUE, TRUE);
}
pa_pstream_send_simple_ack(c->pstream, tag);
@@ -3650,6 +3710,7 @@ static void command_set_mute(
pa_sink *sink = NULL;
pa_source *source = NULL;
pa_sink_input *si = NULL;
+ pa_source_output *so = NULL;
const char *name = NULL, *client_name;
pa_native_connection_assert_ref(c);
@@ -3692,11 +3753,15 @@ static void command_set_mute(
si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
break;
+ case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE:
+ so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
+ break;
+
default:
pa_assert_not_reached();
}
- CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
+ CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
@@ -3711,6 +3776,11 @@ static void command_set_mute(
client_name,
pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
pa_sink_input_set_mute(si, mute, TRUE);
+ } else if (so) {
+ pa_log_debug("Client %s changes mute of source output %s.",
+ client_name,
+ pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
+ pa_source_output_set_mute(so, mute, TRUE);
}
pa_pstream_send_simple_ack(c->pstream, tag);