[player] Fix for volumes of unselected devices being reduced

Closes #1077
This commit is contained in:
ejurgensen 2020-08-13 20:48:48 +02:00
parent 9ecd32771c
commit a5ddb3c85d
3 changed files with 25 additions and 8 deletions

View File

@ -532,9 +532,6 @@ vol_adjust(void)
for (device = outputs_device_list; device; device = device->next)
{
if (!OUTPUTS_DEVICE_DISPLAY_SELECTED(device) && (device->volume > outputs_master_volume))
device->volume = outputs_master_volume;
device->relvol = vol_to_rel(device->volume, outputs_master_volume);
}
@ -815,12 +812,23 @@ outputs_device_remove(struct output_device *remove)
}
void
outputs_device_select(struct output_device *device)
outputs_device_select(struct output_device *device, int max_volume)
{
device->selected = 1;
device->prevent_playback = 0;
device->busy = 0;
// The purpose of this is to cap the volume for a newly selected device. It is
// used by the player to avoid this scenario:
// 1 Play on two speakers, say Kitchen (100) and Office (75), master is 100
// 2 Disable Office, reduce master to 25, Kitchen is now 25, Office is still 75
// 3 Turn on Office, it now blasts at 75
// We could avoid this by reducing the unselected Office in step 2, but that
// leads to issue #1077, where volumes of unselected devices go to 0 (e.g. by
// reducing master to 0 and then increasing again -> unselected stays at 0).
if (max_volume >= 0 && device->volume > max_volume)
device->volume = max_volume;
vol_adjust();
}

View File

@ -291,7 +291,7 @@ void
outputs_device_remove(struct output_device *remove);
void
outputs_device_select(struct output_device *device);
outputs_device_select(struct output_device *device, int max_volume);
void
outputs_device_deselect(struct output_device *device);

View File

@ -2091,7 +2091,7 @@ playback_start_item(void *arg, int *retval)
if (*retval >= 0)
{
DPRINTF(E_LOG, L_PLAYER, "Autoselected %s device '%s'\n", device->type_name, device->name);
outputs_device_select(device);
outputs_device_select(device, -1);
}
}
@ -2561,6 +2561,7 @@ speaker_set(void *arg, int *retval)
struct speaker_set_param *speaker_set_param = arg;
struct output_device *device;
uint64_t *ids;
int max_volume;
int nspk;
int i;
@ -2575,6 +2576,11 @@ speaker_set(void *arg, int *retval)
DPRINTF(E_DBG, L_PLAYER, "Speaker set: %d speakers\n", nspk);
// Save the current master volume before we start selecting/unselecting, as
// that will affect master volume. See comment in outputs_device_select() for
// why we want to provide a max_volume.
max_volume = (player_state != PLAY_STOPPED) ? outputs_volume_get() : -1;
for (device = outputs_list(); device; device = device->next)
{
for (i = 1; i <= nspk; i++)
@ -2584,7 +2590,7 @@ speaker_set(void *arg, int *retval)
}
if (i <= nspk)
outputs_device_select(device);
outputs_device_select(device, max_volume);
else
outputs_device_deselect(device);
}
@ -2602,6 +2608,7 @@ speaker_enable(void *arg, int *retval)
{
uint64_t *id = arg;
struct output_device *device;
int max_volume;
*retval = -1;
@ -2611,7 +2618,9 @@ speaker_enable(void *arg, int *retval)
DPRINTF(E_DBG, L_PLAYER, "Speaker enable: '%s' (id=%" PRIu64 ")\n", device->name, *id);
outputs_device_select(device);
max_volume = (player_state != PLAY_STOPPED) ? outputs_volume_get() : -1;
outputs_device_select(device, max_volume);
*retval = outputs_device_start(device, device_activate_cb, PLAYER_ONLY_PROBE);