diff options
Diffstat (limited to 'libao2/ao_pulse.c')
-rw-r--r-- | libao2/ao_pulse.c | 75 |
1 files changed, 52 insertions, 23 deletions
diff --git a/libao2/ao_pulse.c b/libao2/ao_pulse.c index ba95ccf2d2..5e71f7bf7e 100644 --- a/libao2/ao_pulse.c +++ b/libao2/ao_pulse.c @@ -23,6 +23,7 @@ #include <stdlib.h> #include <stdbool.h> #include <string.h> +#include <stdlib.h> #include <pulse/pulseaudio.h> @@ -45,7 +46,8 @@ struct priv { // Main event loop object struct pa_threaded_mainloop *mainloop; - struct pa_cvolume volume; + // temporary during control() + struct pa_sink_input_info pi; bool broken_pause; int retval; @@ -416,7 +418,7 @@ static void info_func(struct pa_context *c, const struct pa_sink_input_info *i, } if (!i) return; - priv->volume = i->volume; + priv->pi = *i; pa_threaded_mainloop_signal(priv->mainloop, 0); } @@ -424,25 +426,37 @@ static int control(struct ao *ao, int cmd, void *arg) { struct priv *priv = ao->priv; switch (cmd) { + case AOCONTROL_GET_MUTE: // fallthrough case AOCONTROL_GET_VOLUME: { ao_control_vol_t *vol = arg; uint32_t devidx = pa_stream_get_index(priv->stream); pa_threaded_mainloop_lock(priv->mainloop); if (!waitop(priv, pa_context_get_sink_input_info(priv->context, devidx, - info_func, ao))) { + info_func, ao))) + { GENERIC_ERR_MSG(priv->context, "pa_stream_get_sink_input_info() failed"); return CONTROL_ERROR; } - if (priv->volume.channels != 2) - vol->left = vol->right = - pa_cvolume_avg(&priv->volume) * 100 / PA_VOLUME_NORM; - else { - vol->left = priv->volume.values[0] * 100 / PA_VOLUME_NORM; - vol->right = priv->volume.values[1] * 100 / PA_VOLUME_NORM; + // Warning: some information in pi might be unaccessible, because + // we naively copied the struct, without updating pointers etc. + // Pointers might point to invalid data, accessors might fail. + if (cmd == AOCONTROL_GET_VOLUME) { + if (priv->pi.volume.channels != 2) + vol->left = vol->right = + pa_cvolume_avg(&priv->pi.volume) * 100 / PA_VOLUME_NORM; + else { + vol->left = priv->pi.volume.values[0] * 100 / PA_VOLUME_NORM; + vol->right = priv->pi.volume.values[1] * 100 / PA_VOLUME_NORM; + } + } else if (cmd == AOCONTROL_GET_MUTE) { + vol->left = vol->right = priv->pi.mute ? 0.0f : 1.0f; } + return CONTROL_OK; - } + } + + case AOCONTROL_SET_MUTE: // fallthrough case AOCONTROL_SET_VOLUME: { const ao_control_vol_t *vol = arg; pa_operation *o; @@ -451,26 +465,41 @@ static int control(struct ao *ao, int cmd, void *arg) pa_cvolume_reset(&volume, ao->channels); if (volume.channels != 2) pa_cvolume_set(&volume, volume.channels, - (pa_volume_t)vol->left*PA_VOLUME_NORM/100); + (pa_volume_t)vol->left * PA_VOLUME_NORM / 100); else { - volume.values[0] = vol->left * PA_VOLUME_NORM / 100; - volume.values[1] = vol->right * PA_VOLUME_NORM / 100; + volume.values[0] = (pa_volume_t)vol->left * PA_VOLUME_NORM / 100; + volume.values[1] = (pa_volume_t)vol->right * PA_VOLUME_NORM / 100; } + pa_threaded_mainloop_lock(priv->mainloop); - o = pa_context_set_sink_input_volume(priv->context, - pa_stream_get_index(priv->stream), - &volume, NULL, NULL); - if (!o) { - pa_threaded_mainloop_unlock(priv->mainloop); - GENERIC_ERR_MSG(priv->context, - "pa_context_set_sink_input_volume() failed"); - return CONTROL_ERROR; - } + uint32_t stream_index = pa_stream_get_index(priv->stream); + if (cmd == AOCONTROL_SET_VOLUME) { + o = pa_context_set_sink_input_volume(priv->context, stream_index, + &volume, NULL, NULL); + if (!o) { + pa_threaded_mainloop_unlock(priv->mainloop); + GENERIC_ERR_MSG(priv->context, + "pa_context_set_sink_input_volume() failed"); + return CONTROL_ERROR; + } + } else if (cmd == AOCONTROL_SET_MUTE) { + int mute = vol->left == 0.0f || vol->right == 0.0f; + o = pa_context_set_sink_input_mute(priv->context, stream_index, + mute, NULL, NULL); + if (!o) { + pa_threaded_mainloop_unlock(priv->mainloop); + GENERIC_ERR_MSG(priv->context, + "pa_context_set_sink_input_mute() failed"); + return CONTROL_ERROR; + } + } else + abort(); /* We don't wait for completion here */ pa_operation_unref(o); pa_threaded_mainloop_unlock(priv->mainloop); return CONTROL_OK; - } + } + default: return CONTROL_UNKNOWN; } |