summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/modules/alsa/alsa-sink.c2
-rw-r--r--src/modules/module-device-restore.c2
-rw-r--r--src/modules/module-lirc.c6
-rw-r--r--src/modules/module-match.c2
-rw-r--r--src/modules/module-mmkbd-evdev.c6
-rw-r--r--src/modules/module-stream-restore.c142
-rw-r--r--src/modules/oss/module-oss.c2
-rw-r--r--src/pulsecore/cli-command.c6
-rw-r--r--src/pulsecore/cli-text.c15
-rw-r--r--src/pulsecore/protocol-esound.c5
-rw-r--r--src/pulsecore/protocol-native.c9
-rw-r--r--src/pulsecore/sink-input.c55
-rw-r--r--src/pulsecore/sink-input.h8
-rw-r--r--src/pulsecore/sink.c42
-rw-r--r--src/pulsecore/sink.h11
15 files changed, 153 insertions, 160 deletions
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 3e5c219f..2fbcd7be 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -931,7 +931,7 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
return 0;
if (mask & SND_CTL_EVENT_MASK_VALUE) {
- pa_sink_get_volume(u->sink, TRUE);
+ pa_sink_get_volume(u->sink, TRUE, FALSE);
pa_sink_get_mute(u->sink, TRUE);
}
diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c
index 0ca3dd83..7d87ca0f 100644
--- a/src/modules/module-device-restore.c
+++ b/src/modules/module-device-restore.c
@@ -191,7 +191,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
name = pa_sprintf_malloc("sink:%s", sink->name);
entry.channel_map = sink->channel_map;
- entry.volume = *pa_sink_get_volume(sink, FALSE);
+ entry.volume = *pa_sink_get_volume(sink, FALSE, TRUE);
entry.muted = pa_sink_get_mute(sink, FALSE);
} else {
diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c
index 120b26e9..a1a8726f 100644
--- a/src/modules/module-lirc.c
+++ b/src/modules/module-lirc.c
@@ -120,7 +120,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
pa_log("Failed to get sink '%s'", u->sink_name);
else {
int i;
- pa_cvolume cv = *pa_sink_get_volume(s, FALSE);
+ pa_cvolume cv = *pa_sink_get_volume(s, FALSE, FALSE);
#define DELTA (PA_VOLUME_NORM/20)
@@ -133,7 +133,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_MAX;
}
- pa_sink_set_volume(s, &cv, TRUE, TRUE);
+ pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE);
break;
case DOWN:
@@ -144,7 +144,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_MUTED;
}
- pa_sink_set_volume(s, &cv, TRUE, TRUE);
+ pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE);
break;
case MUTE:
diff --git a/src/modules/module-match.c b/src/modules/module-match.c
index d7365ca7..625f2a8b 100644
--- a/src/modules/module-match.c
+++ b/src/modules/module-match.c
@@ -216,7 +216,7 @@ static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, v
pa_cvolume cv;
pa_log_debug("changing volume of sink input '%s' to 0x%03x", n, r->volume);
pa_cvolume_set(&cv, si->sample_spec.channels, r->volume);
- pa_sink_input_set_volume(si, &cv, TRUE);
+ pa_sink_input_set_volume(si, &cv, TRUE, TRUE);
}
}
}
diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c
index c43cfdac..d8b9c79e 100644
--- a/src/modules/module-mmkbd-evdev.c
+++ b/src/modules/module-mmkbd-evdev.c
@@ -102,7 +102,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
pa_log("Failed to get sink '%s'", u->sink_name);
else {
int i;
- pa_cvolume cv = *pa_sink_get_volume(s, FALSE);
+ pa_cvolume cv = *pa_sink_get_volume(s, FALSE, FALSE);
#define DELTA (PA_VOLUME_NORM/20)
@@ -115,7 +115,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_MAX;
}
- pa_sink_set_volume(s, &cv, TRUE, TRUE);
+ pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE);
break;
case DOWN:
@@ -126,7 +126,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_MUTED;
}
- pa_sink_set_volume(s, &cv, TRUE, TRUE);
+ pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE);
break;
case MUTE_TOGGLE:
diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
index 2c90e726..70cd89a7 100644
--- a/src/modules/module-stream-restore.c
+++ b/src/modules/module-stream-restore.c
@@ -91,15 +91,14 @@ struct userdata {
pa_idxset *subscribed;
};
-#define ENTRY_VERSION 1
+#define ENTRY_VERSION 2
struct entry {
uint8_t version;
- pa_bool_t muted_valid:1, relative_volume_valid:1, absolute_volume_valid:1, device_valid:1;
+ pa_bool_t muted_valid:1, volume_valid:1, device_valid:1;
pa_bool_t muted:1;
pa_channel_map channel_map;
- pa_cvolume relative_volume;
- pa_cvolume absolute_volume;
+ pa_cvolume volume;
char device[PA_NAME_MAX];
} PA_GCC_PACKED;
@@ -192,13 +191,12 @@ static struct entry* read_entry(struct userdata *u, const char *name) {
goto fail;
}
- if ((e->relative_volume_valid || e->absolute_volume_valid) && !pa_channel_map_valid(&e->channel_map)) {
+ if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
pa_log_warn("Invalid channel map stored in database for stream %s", name);
goto fail;
}
- if ((e->relative_volume_valid && (!pa_cvolume_valid(&e->relative_volume) || e->relative_volume.channels != e->channel_map.channels)) ||
- (e->absolute_volume_valid && (!pa_cvolume_valid(&e->absolute_volume) || e->absolute_volume.channels != e->channel_map.channels))) {
+ if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
pa_log_warn("Invalid volume stored in database for stream %s", name);
goto fail;
}
@@ -251,14 +249,9 @@ static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
(a->muted_valid && (a->muted != b->muted)))
return FALSE;
- t = b->relative_volume;
- if (a->relative_volume_valid != b->relative_volume_valid ||
- (a->relative_volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->relative_volume)))
- return FALSE;
-
- t = b->absolute_volume;
- if (a->absolute_volume_valid != b->absolute_volume_valid ||
- (a->absolute_volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->absolute_volume)))
+ t = b->volume;
+ if (a->volume_valid != b->volume_valid ||
+ (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
return FALSE;
return TRUE;
@@ -291,22 +284,24 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
if (!(name = get_name(sink_input->proplist, "sink-input")))
return;
- entry.channel_map = sink_input->channel_map;
-
- pa_sink_input_get_relative_volume(sink_input, &entry.relative_volume);
- entry.relative_volume_valid = sink_input->save_volume;
+ if ((old = read_entry(u, name)))
+ entry = *old;
- if (sink_input->sink->flags & PA_SINK_FLAT_VOLUME) {
- entry.absolute_volume = *pa_sink_input_get_volume(sink_input);
- entry.absolute_volume_valid = sink_input->save_volume;
- } else
- entry.absolute_volume_valid = FALSE;
+ if (sink_input->save_volume) {
+ entry.channel_map = sink_input->channel_map;
+ pa_sink_input_get_volume(sink_input, &entry.volume, FALSE);
+ entry.volume_valid = TRUE;
+ }
- entry.muted = pa_sink_input_get_mute(sink_input);
- entry.muted_valid = sink_input->save_muted;
+ if (sink_input->save_muted) {
+ entry.muted = pa_sink_input_get_mute(sink_input);
+ entry.muted_valid = TRUE;
+ }
- pa_strlcpy(entry.device, sink_input->sink->name, sizeof(entry.device));
- entry.device_valid = sink_input->save_sink;
+ if (sink_input->save_sink) {
+ pa_strlcpy(entry.device, sink_input->sink->name, sizeof(entry.device));
+ entry.device_valid = TRUE;
+ }
} else {
pa_source_output *source_output;
@@ -319,13 +314,16 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
if (!(name = get_name(source_output->proplist, "source-output")))
return;
- entry.channel_map = source_output->channel_map;
+ if ((old = read_entry(u, name)))
+ entry = *old;
- pa_strlcpy(entry.device, source_output->source->name, sizeof(entry.device));
- entry.device_valid = source_output->save_source;
+ if (source_output->save_source) {
+ pa_strlcpy(entry.device, source_output->source->name, sizeof(entry.device));
+ entry.device_valid = source_output->save_source;
+ }
}
- if ((old = read_entry(u, name))) {
+ if (old) {
if (entries_equal(old, &entry)) {
pa_xfree(old);
@@ -400,42 +398,24 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
if ((e = read_entry(u, name))) {
- if (u->restore_volume) {
+ if (u->restore_volume && e->volume_valid) {
if (!new_data->volume_is_set) {
pa_cvolume v;
- pa_cvolume_init(&v);
-
- if (new_data->sink->flags & PA_SINK_FLAT_VOLUME) {
-
- /* We don't check for e->device_valid here because
- that bit marks whether it is a good choice for
- restoring, not just if the data is filled in. */
- if (e->absolute_volume_valid &&
- (e->device[0] == 0 || pa_streq(new_data->sink->name, e->device))) {
-
- v = e->absolute_volume;
- new_data->volume_is_absolute = TRUE;
- } else if (e->relative_volume_valid) {
- v = e->relative_volume;
- new_data->volume_is_absolute = FALSE;
- }
-
- } else if (e->relative_volume_valid) {
- v = e->relative_volume;
- new_data->volume_is_absolute = FALSE;
- }
- if (v.channels > 0) {
- pa_log_info("Restoring volume for sink input %s.", name);
- pa_sink_input_new_data_set_volume(new_data, pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map));
- new_data->save_volume = TRUE;
- }
+ pa_log_info("Restoring volume for sink input %s.", name);
+ v = e->volume;
+ pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
+ pa_sink_input_new_data_set_volume(new_data, &v);
+
+ new_data->volume_is_absolute = FALSE;
+ new_data->save_volume = FALSE;
} else
pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
}
if (u->restore_muted && e->muted_valid) {
+
if (!new_data->muted_is_set) {
pa_log_info("Restoring mute state for sink input %s.", name);
pa_sink_input_new_data_set_muted(new_data, e->muted);
@@ -532,30 +512,15 @@ static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
}
pa_xfree(n);
- if (u->restore_volume) {
+ if (u->restore_volume && e->volume_valid) {
pa_cvolume v;
- pa_cvolume_init(&v);
- if (si->sink->flags & PA_SINK_FLAT_VOLUME) {
-
- if (e->absolute_volume_valid &&
- (e->device[0] == 0 || pa_streq(e->device, si->sink->name)))
- v = e->absolute_volume;
- else if (e->relative_volume_valid) {
- pa_cvolume t = *pa_sink_get_volume(si->sink, FALSE);
- pa_sw_cvolume_multiply(&v, &e->relative_volume, pa_cvolume_remap(&t, &si->sink->channel_map, &e->channel_map));
- }
- } else if (e->relative_volume_valid)
- v = e->relative_volume;
-
- if (v.channels > 0) {
- pa_log_info("Restoring volume for sink input %s.", name);
- pa_sink_input_set_volume(si, pa_cvolume_remap(&v, &e->channel_map, &si->channel_map), TRUE);
- }
+ v = e->volume;
+ pa_log_info("Restoring volume for sink input %s.", name);
+ pa_sink_input_set_volume(si, pa_cvolume_remap(&v, &e->channel_map, &si->channel_map), FALSE, FALSE);
}
- if (u->restore_muted &&
- e->muted_valid) {
+ if (u->restore_muted && e->muted_valid) {
pa_log_info("Restoring mute state for sink input %s.", name);
pa_sink_input_set_mute(si, e->muted, TRUE);
}
@@ -610,10 +575,10 @@ static void dump_database(struct userdata *u) {
if ((e = read_entry(u, name))) {
char t[256];
pa_log("name=%s", name);
- pa_log("device=%s", e->device);
+ pa_log("device=%s %s", e->device, pa_yes_no(e->device_valid));
pa_log("channel_map=%s", pa_channel_map_snprint(t, sizeof(t), &e->channel_map));
- pa_log("volume=%s", pa_cvolume_snprint(t, sizeof(t), &e->volume));
- pa_log("mute=%s", pa_yes_no(e->muted));
+ pa_log("volume=%s %s", pa_cvolume_snprint(t, sizeof(t), &e->volume), pa_yes_no(e->volume_valid));
+ pa_log("mute=%s %s", pa_yes_no(e->muted), pa_yes_no(e->volume_valid));
pa_xfree(e);
}
@@ -674,8 +639,8 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
pa_channel_map cm;
pa_tagstruct_puts(reply, name);
- pa_tagstruct_put_channel_map(reply, (e->relative_volume_valid || e->absolute_volume_valid) ? &e->channel_map : pa_channel_map_init(&cm));
- pa_tagstruct_put_cvolume(reply, e->absolute_volume_valid ? &e->absolute_volume : (e->relative_volume_valid ? &e->relative_volume : pa_cvolume_init(&r)));
+ pa_tagstruct_put_channel_map(reply, e->volume_valid ? &e->channel_map : pa_channel_map_init(&cm));
+ pa_tagstruct_put_cvolume(reply, e->volume_valid ? &e->volume : pa_cvolume_init(&r));
pa_tagstruct_puts(reply, e->device_valid ? e->device : NULL);
pa_tagstruct_put_boolean(reply, e->muted_valid ? e->muted : FALSE);
@@ -718,7 +683,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
if (pa_tagstruct_gets(t, &name) < 0 ||
pa_tagstruct_get_channel_map(t, &entry.channel_map) ||
- pa_tagstruct_get_cvolume(t, &entry.absolute_volume) < 0 ||
+ pa_tagstruct_get_cvolume(t, &entry.volume) < 0 ||
pa_tagstruct_gets(t, &device) < 0 ||
pa_tagstruct_get_boolean(t, &muted) < 0)
goto fail;
@@ -726,11 +691,10 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
if (!name || !*name)
goto fail;
- entry.relative_volume = entry.absolute_volume;
- entry.absolute_volume_valid = entry.relative_volume_valid = entry.relative_volume.channels > 0;
+ entry.volume_valid = entry.volume.channels > 0;
- if (entry.relative_volume_valid)
- if (!pa_cvolume_compatible_with_channel_map(&entry.relative_volume, &entry.channel_map))
+ if (entry.volume_valid)
+ if (!pa_cvolume_compatible_with_channel_map(&entry.volume, &entry.channel_map))
goto fail;
entry.muted = muted;
diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c
index 855e8a35..9f7863f5 100644
--- a/src/modules/oss/module-oss.c
+++ b/src/modules/oss/module-oss.c
@@ -617,7 +617,7 @@ static int unsuspend(struct userdata *u) {
build_pollfd(u);
if (u->sink)
- pa_sink_get_volume(u->sink, TRUE);
+ pa_sink_get_volume(u->sink, TRUE, FALSE);
if (u->source)
pa_source_get_volume(u->source, TRUE);
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index 3ea1dca5..15fe525c 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -524,7 +524,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
}
pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume);
- pa_sink_set_volume(sink, &cvolume, TRUE, TRUE);
+ pa_sink_set_volume(sink, &cvolume, TRUE, TRUE, TRUE);
return 0;
}
@@ -566,7 +566,7 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb
}
pa_cvolume_set(&cvolume, si->sample_spec.channels, volume);
- pa_sink_input_set_volume(si, &cvolume, TRUE);
+ pa_sink_input_set_volume(si, &cvolume, TRUE, TRUE);
return 0;
}
@@ -1516,7 +1516,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b
nl = 1;
}
- pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, FALSE)));
+ pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, FALSE, TRUE)));
pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, FALSE)));
pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(pa_sink_get_state(sink) == PA_SINK_SUSPENDED));
}
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index b0911ef1..604678be 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -258,10 +258,10 @@ char *pa_sink_list_to_string(pa_core *c) {
sink->flags & PA_SINK_FLAT_VOLUME ? "FLAT_VOLUME " : "",
sink->flags & PA_SINK_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "",
sink_state_to_string(pa_sink_get_state(sink)),
- pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)),
+ pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE, FALSE)),
sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
- sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE)) : "",
- pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE), &sink->channel_map),
+ sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE, FALSE)) : "",
+ pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE, FALSE), &sink->channel_map),
pa_volume_snprint(v, sizeof(v), sink->base_volume),
sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), sink->base_volume) : "",
@@ -507,6 +507,9 @@ char *pa_sink_input_list_to_string(pa_core *c) {
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t, clt[28];
pa_usec_t cl;
const char *cmn;
+ pa_cvolume v;
+
+ pa_sink_input_get_volume(i, &v, TRUE);
cmn = pa_channel_map_to_pretty_name(&i->channel_map);
@@ -547,9 +550,9 @@ char *pa_sink_input_list_to_string(pa_core *c) {
i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND ? "FAIL_ON_SUSPEND " : "",
state_table[pa_sink_input_get_state(i)],
i->sink->index, i->sink->name,
- pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)),
- pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_input_get_volume(i)),
- pa_cvolume_get_balance(pa_sink_input_get_volume(i), &i->channel_map),
+ pa_cvolume_snprint(cv, sizeof(cv), &v),
+ pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &v),
+ pa_cvolume_get_balance(&v, &i->channel_map),
pa_yes_no(pa_sink_input_get_mute(i)),
(double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC,
clt,
diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c
index a024471c..7e7126ea 100644
--- a/src/pulsecore/protocol-esound.c
+++ b/src/pulsecore/protocol-esound.c
@@ -638,7 +638,8 @@ static int esd_proto_all_info(connection *c, esd_proto_t request, const void *da
pa_assert(t >= k*2+s);
if (conn->sink_input) {
- pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input);
+ pa_cvolume volume;
+ pa_sink_input_get_volume(conn->sink_input, &volume, TRUE);
rate = (int32_t) conn->sink_input->sample_spec.rate;
lvolume = (int32_t) ((volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
rvolume = (int32_t) ((volume.values[volume.channels == 2 ? 1 : 0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
@@ -778,7 +779,7 @@ static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void *
volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE;
volume.channels = conn->sink_input->sample_spec.channels;
- pa_sink_input_set_volume(conn->sink_input, &volume, TRUE);
+ pa_sink_input_set_volume(conn->sink_input, &volume, TRUE, TRUE);
ok = 1;
} else
ok = 0;
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 7c2183d8..aecaf71c 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -2819,7 +2819,7 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin
PA_TAG_SAMPLE_SPEC, &fixed_ss,
PA_TAG_CHANNEL_MAP, &sink->channel_map,
PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
- PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
+ PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE, FALSE),
PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
@@ -2943,6 +2943,7 @@ static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_m
static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
pa_sample_spec fixed_ss;
pa_usec_t sink_latency;
+ pa_cvolume v;
pa_assert(t);
pa_sink_input_assert_ref(s);
@@ -2956,7 +2957,7 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t,
pa_tagstruct_putu32(t, s->sink->index);
pa_tagstruct_put_sample_spec(t, &fixed_ss);
pa_tagstruct_put_channel_map(t, &s->channel_map);
- pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s));
+ pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s, &v, TRUE));
pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
pa_tagstruct_put_usec(t, sink_latency);
pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
@@ -3321,11 +3322,11 @@ static void command_set_volume(
CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
if (sink)
- pa_sink_set_volume(sink, &volume, TRUE, TRUE);
+ pa_sink_set_volume(sink, &volume, TRUE, TRUE, TRUE);
else if (source)
pa_source_set_volume(source, &volume);
else if (si)
- pa_sink_input_set_volume(si, &volume, TRUE);
+ pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
pa_pstream_send_simple_ack(c->pstream, tag);
}
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index b1b9fb56..65f1fd5e 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -176,16 +176,8 @@ int pa_sink_input_new(
pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID);
if (!data->volume_is_set) {
-
- if (data->sink->flags & PA_SINK_FLAT_VOLUME) {
- data->volume = *pa_sink_get_volume(data->sink, FALSE);
- pa_cvolume_remap(&data->volume, &data->sink->channel_map, &data->channel_map);
- data->volume_is_absolute = TRUE;
- } else {
- pa_cvolume_reset(&data->volume, data->sample_spec.channels);
- data->volume_is_absolute = FALSE;
- }
-
+ pa_cvolume_reset(&data->volume, data->sample_spec.channels);
+ data->volume_is_absolute = FALSE;
data->save_volume = FALSE;
}
@@ -279,10 +271,9 @@ int pa_sink_input_new(
/* When the 'absolute' bool is not set then we'll treat the volume
* as relative to the sink volume even in flat volume mode */
- pa_cvolume t = *pa_sink_get_volume(data->sink, FALSE);
- pa_cvolume_remap(&t, &data->sink->channel_map, &data->channel_map);
-
- pa_sw_cvolume_multiply(&i->virtual_volume, &data->volume, &t);
+ pa_cvolume v = data->sink->reference_volume;
+ pa_cvolume_remap(&v, &data->sink->channel_map, &data->channel_map);
+ pa_sw_cvolume_multiply(&i->virtual_volume, &data->volume, &v);
} else
i->virtual_volume = data->volume;
@@ -451,7 +442,7 @@ void pa_sink_input_unlink(pa_sink_input *i) {
if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
pa_cvolume new_volume;
pa_sink_update_flat_volume(i->sink, &new_volume);
- pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+ pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
}
if (i->sink->asyncmsgq)
@@ -529,7 +520,7 @@ void pa_sink_input_put(pa_sink_input *i) {
if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
pa_cvolume new_volume;
pa_sink_update_flat_volume(i->sink, &new_volume);
- pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+ pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
} else
pa_sink_input_set_relative_volume(i, &i->virtual_volume);
@@ -881,13 +872,21 @@ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) {
}
/* Called from main context */
-void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save) {
+void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute) {
+ pa_cvolume v;
+
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
pa_assert(volume);
pa_assert(pa_cvolume_valid(volume));
pa_assert(pa_cvolume_compatible(volume, &i->sample_spec));
+ if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
+ v = i->sink->reference_volume;
+ pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map);
+ volume = pa_sw_cvolume_multiply(&v, &v, volume);
+ }
+
if (pa_cvolume_equal(volume, &i->virtual_volume))
return;
@@ -901,7 +900,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
* volumes and update the flat volume of the sink */
pa_sink_update_flat_volume(i->sink, &new_volume);
- pa_sink_set_volume(i->sink, &new_volume, FALSE, TRUE);
+ pa_sink_set_volume(i->sink, &new_volume, FALSE, TRUE, FALSE);
} else {
@@ -921,11 +920,18 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
}
/* Called from main context */
-const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) {
+pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute) {
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
- return &i->virtual_volume;
+ if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
+ pa_cvolume v = i->sink->reference_volume;
+ pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map);
+ pa_sw_cvolume_divide(volume, &i->virtual_volume, &v);
+ } else
+ *volume = i->virtual_volume;
+
+ return volume;
}
/* Called from main context */
@@ -936,7 +942,8 @@ pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) {
pa_assert(v);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
- /* This always returns a relative volume, even in flat volume mode */
+ /* This always returns the relative volume. Converts the float
+ * version into a pa_cvolume */
v->channels = i->sample_spec.channels;
@@ -1152,7 +1159,7 @@ int pa_sink_input_start_move(pa_sink_input *i) {
/* We might need to update the sink's volume if we are in flat
* volume mode. */
pa_sink_update_flat_volume(i->sink, &new_volume);
- pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+ pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
}
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0);
@@ -1239,13 +1246,13 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
pa_cvolume new_volume;
/* Make relative volume absolute again */
- pa_cvolume t = dest->virtual_volume;
+ pa_cvolume t = dest->reference_volume;
pa_cvolume_remap(&t, &dest->channel_map, &i->channel_map);
pa_sw_cvolume_multiply(&i->virtual_volume, &i->virtual_volume, &t);
/* We might need to update the sink's volume if we are in flat volume mode. */
pa_sink_update_flat_volume(i->sink, &new_volume);
- pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+ pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
}
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0);
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 96ad2baf..98144d41 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -91,6 +91,7 @@ struct pa_sink_input {
pa_sink_input *sync_prev, *sync_next;
+ /* Also see http://pulseaudio.org/wiki/InternalVolumes */
pa_cvolume virtual_volume; /* The volume clients are informed about */
pa_cvolume volume_factor; /* An internally used volume factor that can be used by modules to apply effects and suchlike without having that visible to the outside */
double relative_volume[PA_CHANNELS_MAX]; /* The calculated volume relative to the sink volume as linear factors. */
@@ -309,11 +310,14 @@ void pa_sink_input_kill(pa_sink_input*i);
pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency);
-void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save);
-const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i);
+void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute);
+pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute);
+
pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v);
+
void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save);
pa_bool_t pa_sink_input_get_mute(pa_sink_input *i);
+
void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p);
pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i);
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 93800d14..30fa5579 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -202,7 +202,7 @@ pa_sink* pa_sink_new(
s->inputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
- s->virtual_volume = data->volume;
+ s->reference_volume = s->virtual_volume = data->volume;
pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
s->base_volume = PA_VOLUME_NORM;
s->n_volume_steps = PA_VOLUME_NORM+1;
@@ -351,11 +351,12 @@ void pa_sink_put(pa_sink* s) {
if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) {
s->flags |= PA_SINK_DECIBEL_VOLUME;
-
- s->thread_info.soft_volume = s->soft_volume;
- s->thread_info.soft_muted = s->muted;
+ s->base_volume = PA_VOLUME_NORM;
}
+ s->thread_info.soft_volume = s->soft_volume;
+ s->thread_info.soft_muted = s->muted;
+
if (s->flags & PA_SINK_DECIBEL_VOLUME)
s->n_volume_steps = PA_VOLUME_NORM+1;
@@ -1046,16 +1047,16 @@ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
pa_assert(PA_SINK_IS_LINKED(s->state));
pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
- /* This is called whenever a sink input volume changes and we
- * might need to fix up the sink volume accordingly. Please note
- * that we don't actually update the sinks volume here, we only
- * return how it needs to be updated. The caller should then call
- * pa_sink_set_volume().*/
+ /* This is called whenever a sink input volume changes or a sink
+ * input is added/removed and we might need to fix up the sink
+ * volume accordingly. Please note that we don't actually update
+ * the sinks volume here, we only return how it needs to be
+ * updated. The caller should then call pa_sink_set_volume().*/
if (pa_idxset_isempty(s->inputs)) {
/* In the special case that we have no sink input we leave the
* volume unmodified. */
- *new_volume = s->virtual_volume;
+ *new_volume = s->reference_volume;
return;
}
@@ -1142,7 +1143,7 @@ void pa_sink_propagate_flat_volume(pa_sink *s) {
}
/* Called from main thread */
-void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg) {
+void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference) {
pa_bool_t virtual_volume_changed;
pa_sink_assert_ref(s);
@@ -1154,6 +1155,9 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat
virtual_volume_changed = !pa_cvolume_equal(volume, &s->virtual_volume);
s->virtual_volume = *volume;
+ if (become_reference)
+ s->reference_volume = s->virtual_volume;
+
/* Propagate this volume change back to the inputs */
if (virtual_volume_changed)
if (propagate && (s->flags & PA_SINK_FLAT_VOLUME))
@@ -1161,8 +1165,8 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat
if (s->set_volume) {
/* If we have a function set_volume(), then we do not apply a
- * soft volume by default. However, set_volume() is apply one
- * to s->soft_volume */
+ * soft volume by default. However, set_volume() is free to
+ * apply one to s->soft_volume */
pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
s->set_volume(s);
@@ -1194,7 +1198,7 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
}
/* Called from main thread */
-const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
+const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_bool_t reference) {
pa_sink_assert_ref(s);
if (s->refresh_volume || force_refresh) {
@@ -1207,6 +1211,8 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
+ s->reference_volume = s->virtual_volume;
+
if (s->flags & PA_SINK_FLAT_VOLUME)
pa_sink_propagate_flat_volume(s);
@@ -1214,7 +1220,7 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
}
}
- return &s->virtual_volume;
+ return reference ? &s->reference_volume : &s->virtual_volume;
}
/* Called from main thread */
@@ -1226,7 +1232,11 @@ void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) {
if (pa_cvolume_equal(&s->virtual_volume, new_volume))
return;
- s->virtual_volume = *new_volume;
+ s->reference_volume = s->virtual_volume = *new_volume;
+
+ if (s->flags & PA_SINK_FLAT_VOLUME)
+ pa_sink_propagate_flat_volume(s);
+
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index cb4697f9..352282b8 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -74,8 +74,10 @@ struct pa_sink {
pa_volume_t base_volume; /* shall be constant */
unsigned n_volume_steps; /* shall be constant */
- pa_cvolume virtual_volume; /* The volume clients are informed about */
- pa_cvolume soft_volume; /* The internal software volume we apply to all PCM data while it passes through */
+ /* Also see http://pulseaudio.org/wiki/InternalVolumes */
+ pa_cvolume virtual_volume; /* The volume clients are informed about */
+ pa_cvolume reference_volume; /* The volume taken as refernce base for relative sink input volumes */
+ pa_cvolume soft_volume; /* The internal software volume we apply to all PCM data while it passes through */
pa_bool_t muted:1;
pa_bool_t refresh_volume:1;
@@ -255,8 +257,9 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend);
void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume);
void pa_sink_propagate_flat_volume(pa_sink *s);
-void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg);
-const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh);
+void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference);
+const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh, pa_bool_t reference);
+
void pa_sink_set_mute(pa_sink *sink, pa_bool_t mute);
pa_bool_t pa_sink_get_mute(pa_sink *sink, pa_bool_t force_refresh);