static void sink_set_volume_cb(pa_sink *s) { struct userdata *u = s->userdata; pa_cvolume hw; pa_volume_t v; char t[PA_CVOLUME_SNPRINT_VERBOSE_MAX]; pa_assert(u); /* If we're muted we don't need to do anything */ if (s->muted) return; /* 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->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->real_volume, &hw); pa_log_debug("Requested volume: %s", pa_cvolume_snprint_verbose(t, sizeof(t), &s->real_volume, &s->channel_map, false)); pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint_verbose(t, sizeof(t), &hw, &s->channel_map, false)); pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint_verbose(t, sizeof(t), &s->soft_volume, &s->channel_map, true)); /* Any necessary software volume manipulation is done so set our hw volume (or v as a single value) on the device */ pa_raop_client_set_volume(u->raop, v); }
static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *core, pa_sink_input_new_data *data, struct userdata *u) { const char *hpos, *vpos, *role, *id; double f; char t[PA_CVOLUME_SNPRINT_VERBOSE_MAX]; pa_cvolume v; pa_assert(data); if (!(role = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_ROLE))) return PA_HOOK_OK; if (!pa_streq(role, "event")) return PA_HOOK_OK; if ((id = pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID))) { /* The test sounds should never be positioned in space, since * they might be triggered themselves to configure the speakers * in space, which we don't want to mess up. */ if (pa_startswith(id, "audio-channel-")) return PA_HOOK_OK; if (pa_streq(id, "audio-volume-change")) return PA_HOOK_OK; if (pa_streq(id, "audio-test-signal")) return PA_HOOK_OK; } if (!(hpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_HPOS))) hpos = pa_proplist_gets(data->proplist, PA_PROP_WINDOW_HPOS); if (!(vpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_VPOS))) vpos = pa_proplist_gets(data->proplist, PA_PROP_WINDOW_VPOS); if (!hpos && !vpos) return PA_HOOK_OK; pa_cvolume_reset(&v, data->sink->sample_spec.channels); if (hpos) { if (parse_pos(hpos, &f) < 0) return PA_HOOK_OK; if (pa_channel_map_can_balance(&data->sink->channel_map)) { pa_log_debug("Positioning event sound '%s' horizontally at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); pa_cvolume_set_balance(&v, &data->sink->channel_map, f*2.0-1.0); } } if (vpos) { if (parse_pos(vpos, &f) < 0) return PA_HOOK_OK; if (pa_channel_map_can_fade(&data->sink->channel_map)) { pa_log_debug("Positioning event sound '%s' vertically at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); pa_cvolume_set_fade(&v, &data->sink->channel_map, f*2.0-1.0); } } pa_log_debug("Final volume factor %s.", pa_cvolume_snprint_verbose(t, sizeof(t), &v, &data->sink->channel_map, data->sink->flags & PA_SINK_DECIBEL_VOLUME)); pa_sink_input_new_data_add_volume_factor_sink(data, u->name, &v); return PA_HOOK_OK; }