summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2009-04-13 22:50:24 +0200
committerLennart Poettering <lennart@poettering.net>2009-04-13 22:56:25 +0200
commitfe8b10cc05b3b8e8633ffaff30e73a40a30c8bf8 (patch)
treed8f435ba2da3b2ea7d88a66b39a2bcc63a07b7d8 /src
parent49dcf0940e6024f788eeaaf33012eb8b48c3d8ae (diff)
core: introduce new 'reference' volume for sinks
The reference volume is to be used as reference volume for stored stream volumes. Previously if a new stream was created the relative volume was taken relatively to the virtual device volume. Due to the flat volume logic this could then be fed back to the virtual device volume. Repeating the whole story over and over would result in a device volume that would go lower, and lower and lower. This patch introduces a 'reference' volume for each sink which stays unmodified by stream volume changes even if flat volumes are used. It is only modified if the sink volumes are modified directly by the user. For further explanations see http://pulseaudio.org/wiki/InternalVolumes
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);