sink: volume handling rework, new flat volume logic

- We now implement a logic where the sink maintains two distinct
  volumes: the 'reference' volume which is shown to the users, and the
  'real' volume, which is configured to the hardware. The latter is
  configured to the max of all streams. Volume changes on sinks are
  propagated back to the streams proportional to the reference volume
  change. Volume changes on sink inputs are forwarded to the sink by
  'pushing' the volume if necessary.

  This renames the old 'virtual_volume' to 'real_volume'. The
  'reference_volume' is now the one exposed to users.

  By this logic the sink volume visible to the user, will always be the
  "upper" boundary for everything that is played. Saved/restored stream
  volumes are measured relative to this boundary, the factor here is
  always < 1.0.

- introduce accuracy for sink volumes, similar to the accuracy we
  already have for source volumes.

- other cleanups.
This commit is contained in:
Lennart Poettering 2009-08-19 02:55:02 +02:00
parent 5207e19142
commit 8c31974f56
16 changed files with 342 additions and 295 deletions

View file

@ -1009,7 +1009,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, FALSE);
pa_sink_get_volume(u->sink, TRUE);
pa_sink_get_mute(u->sink, TRUE);
}

View file

@ -218,7 +218,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
if (sink->save_volume) {
entry.channel_map = sink->channel_map;
entry.volume = *pa_sink_get_volume(sink, FALSE, TRUE);
entry.volume = *pa_sink_get_volume(sink, FALSE);
entry.volume_valid = TRUE;
}

View file

@ -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, FALSE);
pa_cvolume cv = *pa_sink_get_volume(s, FALSE);
#define DELTA (PA_VOLUME_NORM/20)

View file

@ -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, TRUE);
pa_sink_input_set_volume(si, &cv, TRUE, FALSE);
}
}
}

View file

@ -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, FALSE);
pa_cvolume cv = *pa_sink_get_volume(s, 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, TRUE, TRUE);
pa_sink_set_volume(s, &cv, 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, TRUE, TRUE);
pa_sink_set_volume(s, &cv, TRUE, TRUE);
break;
case MUTE_TOGGLE:

View file

@ -1162,7 +1162,7 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag
pa_assert(u->sink);
if ((u->version < 11 || !!mute == !!u->sink->muted) &&
pa_cvolume_equal(&volume, &u->sink->virtual_volume))
pa_cvolume_equal(&volume, &u->sink->real_volume))
return;
pa_sink_volume_changed(u->sink, &volume);
@ -1763,7 +1763,7 @@ static void sink_set_volume(pa_sink *sink) {
pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME);
pa_tagstruct_putu32(t, tag = u->ctag++);
pa_tagstruct_putu32(t, u->device_index);
pa_tagstruct_put_cvolume(t, &sink->virtual_volume);
pa_tagstruct_put_cvolume(t, &sink->real_volume);
pa_pstream_send_tagstruct(u->pstream, t);
}

View file

@ -812,11 +812,11 @@ static void sink_get_volume(pa_sink *s) {
pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
if (u->mixer_devmask & SOUND_MASK_VOLUME)
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->virtual_volume) >= 0)
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->real_volume) >= 0)
return;
if (u->mixer_devmask & SOUND_MASK_PCM)
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->virtual_volume) >= 0)
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->real_volume) >= 0)
return;
pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
@ -830,11 +830,11 @@ static void sink_set_volume(pa_sink *s) {
pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
if (u->mixer_devmask & SOUND_MASK_VOLUME)
if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->virtual_volume) >= 0)
if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->real_volume) >= 0)
return;
if (u->mixer_devmask & SOUND_MASK_PCM)
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->virtual_volume) >= 0)
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->real_volume) >= 0)
return;
pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));

View file

@ -283,15 +283,15 @@ static void sink_set_volume_cb(pa_sink *s) {
/* Calculate the max volume of all channels.
We'll use this as our (single) volume on the APEX device and emulate
any variation in channel volumes in software */
v = pa_cvolume_max(&s->virtual_volume);
v = pa_cvolume_max(&s->real_volume);
/* Create a pa_cvolume version of our single value */
pa_cvolume_set(&hw, s->sample_spec.channels, v);
/* Perform any software manipulation of the volume needed */
pa_sw_cvolume_divide(&s->soft_volume, &s->virtual_volume, &hw);
pa_sw_cvolume_divide(&s->soft_volume, &s->real_volume, &hw);
pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->virtual_volume));
pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->real_volume));
pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &hw));
pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->soft_volume));