From a40958cdf87ba593015a9198e28d4805aca23929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 4 Jan 2023 01:35:43 +0000 Subject: [PATCH] ao_pipewire: allow usage of global volume control PipeWire supports a global volume control for streams that works on top of the per-channel volumes. As mpv only supports a single volume with ao-volume it can make sense to use the single global volume from PipeWire for it. This allows the user to also specify per-channel volumes and not have mpv trample over them. This mode is not the default as pulseaudio does not support this global volume control and all tooling controlling PipeWire via pipewire-pulse (like pavucontrol) will not be able to see this channel. --- DOCS/man/ao.rst | 5 +++++ audio/out/ao_pipewire.c | 34 +++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/DOCS/man/ao.rst b/DOCS/man/ao.rst index 4f9436b157..bd621630d2 100644 --- a/DOCS/man/ao.rst +++ b/DOCS/man/ao.rst @@ -161,6 +161,11 @@ Available audio output drivers are: sockets. An empty string uses the default remote named ``pipewire-0``. + ``--pipewire-volume-mode=`` + Specify if the ``ao-volume`` property should apply to the channel + volumes or the global volume. + By default the channel volumes are used. + ``sdl`` SDL 1.2+ audio output driver. Should work on any platform supported by SDL 1.2, but may require the ``SDL_AUDIODRIVER`` environment variable to be set diff --git a/audio/out/ao_pipewire.c b/audio/out/ao_pipewire.c index 448dbaa5fc..5b048a56e7 100644 --- a/audio/out/ao_pipewire.c +++ b/audio/out/ao_pipewire.c @@ -61,6 +61,11 @@ enum init_state { INIT_STATE_ERROR, }; +enum { + VOLUME_MODE_CHANNEL, + VOLUME_MODE_GLOBAL, +}; + struct priv { struct pw_thread_loop *loop; struct pw_stream *stream; @@ -75,6 +80,7 @@ struct priv { struct { int buffer_msec; char *remote; + int volume_mode; } options; struct { @@ -280,9 +286,17 @@ static void on_control_info(void *userdata, uint32_t id, p->muted = control->values[0] >= 0.5; break; case SPA_PROP_channelVolumes: + if (p->options.volume_mode != VOLUME_MODE_CHANNEL) + break; if (control->n_values > 0) p->volume = volume_avg(control->values, control->n_values); break; + case SPA_PROP_volume: + if (p->options.volume_mode != VOLUME_MODE_GLOBAL) + break; + if (control->n_values > 0) + p->volume = control->values[0]; + break; } } @@ -663,12 +677,19 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg) case AOCONTROL_SET_VOLUME: { float *vol = arg; uint8_t n = ao->channels.num; - float values[MP_NUM_CHANNELS] = {0}; - for (int i = 0; i < n; i++) - values[i] = mp_volume_to_spa_volume(*vol); - ret = CONTROL_RET(pw_stream_set_control(p->stream, SPA_PROP_channelVolumes, n, values, 0)); + if (p->options.volume_mode == VOLUME_MODE_CHANNEL) { + float values[MP_NUM_CHANNELS] = {0}; + for (int i = 0; i < n; i++) + values[i] = mp_volume_to_spa_volume(*vol); + ret = CONTROL_RET(pw_stream_set_control( + p->stream, SPA_PROP_channelVolumes, n, values, 0)); + } else { + float value = mp_volume_to_spa_volume(*vol); + ret = CONTROL_RET(pw_stream_set_control( + p->stream, SPA_PROP_volume, 1, &value, 0)); + } break; - } + } case AOCONTROL_SET_MUTE: { bool *muted = arg; float value = *muted ? 1.f : 0.f; @@ -854,11 +875,14 @@ const struct ao_driver audio_out_pipewire = { .stream = NULL, .init_state = INIT_STATE_NONE, .options.buffer_msec = 20, + .options.volume_mode = VOLUME_MODE_CHANNEL, }, .options_prefix = "pipewire", .options = (const struct m_option[]) { {"buffer", OPT_INT(options.buffer_msec), M_RANGE(1, 2000)}, {"remote", OPT_STRING(options.remote) }, + {"volume-mode", OPT_CHOICE(options.volume_mode, + {"channel", VOLUME_MODE_CHANNEL}, {"global", VOLUME_MODE_GLOBAL})}, {0} }, };