2 * module-murphy-ivi -- PulseAudio module for providing audio routing support
3 * Copyright (c) 2012, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU Lesser General Public License,
7 * version 2.1, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
25 #include <pulsecore/pulsecore-config.h>
27 #include <pulse/proplist.h>
28 #include <pulsecore/core-util.h>
29 #include <pulsecore/sink.h>
30 #include <pulsecore/sink-input.h>
45 transition_time transit;
48 static void set_stream_volume_limit(struct userdata *, pa_sink_input *,
51 pa_fader *pa_fader_init(const char *fade_out_str, const char *fade_in_str)
53 pa_fader *fader = pa_xnew0(pa_fader, 1);
55 if (!fade_out_str || pa_atol(fade_out_str, &fader->transit.fade_out) < 0)
56 fader->transit.fade_out = 100;
58 if (!fade_in_str || pa_atol(fade_in_str, &fader->transit.fade_in) < 0)
59 fader->transit.fade_in = 1000;
61 if (fader->transit.fade_out > 10000)
62 fader->transit.fade_out = 10000;
64 if (fader->transit.fade_in > 10000)
65 fader->transit.fade_in = 10000;
67 pa_log_info("fader transition times: out %ld ms, in %ld ms",
68 fader->transit.fade_out, fader->transit.fade_in);
73 void pa_fader_done(struct userdata *u)
82 void pa_fader_apply_volume_limits(struct userdata *u, uint32_t stamp)
85 transition_time *transit;
87 pa_sink_input *sinp, *origin;
88 pa_cvolume_ramp_int *ramp;
89 mir_node *device_node;
90 mir_node *stream_node;
103 pa_assert_se(u->fader);
104 pa_assert_se((core = u->core));
106 transit = &u->fader->transit;
107 rampit = transit->fade_in > 0 && transit->fade_out > 0;
109 pa_log_debug("applying volume limits ...");
111 PA_IDXSET_FOREACH(sink, core->sinks, i) {
112 if ((device_node = pa_discover_find_node_by_ptr(u, sink))) {
113 pa_log_debug(" node '%s'", device_node->amname);
117 PA_IDXSET_FOREACH(sinp, sink->inputs, j) {
118 origin = pa_utils_get_stream_origin(u, sinp);
119 stream_node = pa_discover_find_node_by_ptr(u, origin);
121 if ((class = pa_utils_get_stream_class(sinp->proplist)) > 0) {
123 corked = stream_node ? !stream_node->rset.grant : false;
124 muted = (sinp->muted || pa_hashmap_get(sinp->volume_factor_items,
126 if (origin != sinp) {
127 muted |= (origin->muted || pa_hashmap_get(origin->volume_factor_items,
131 if (!corked && !muted)
132 mask |= mir_volume_get_class_mask(class);
134 pa_log_debug("*** stream %u (origin %u) class: %d corked: %s muted: %s "
135 "(sinp:%s internal:%s)", sinp->index, origin->index,
136 class, corked?"yes":"no ",
137 muted?"yes":"no", sinp->muted ? "yes":"no",
138 pa_hashmap_get(sinp->volume_factor_items,"internal_mute")?"yes":"no");
141 pa_log_debug("*** steam %u (origin %u) class: %d", sinp->index, origin->index, class);
144 pa_log_debug("*** mask: 0x%x", mask);
146 PA_IDXSET_FOREACH(sinp, sink->inputs, j) {
147 class = pa_utils_get_stream_class(sinp->proplist);
149 pa_log_debug(" stream %u (class %u)", sinp->index, class);
152 if (!(sinp->flags & PA_SINK_INPUT_START_RAMP_MUTED))
153 pa_log_debug(" skipping");
155 sinp->flags &= ~((unsigned int)PA_SINK_INPUT_START_RAMP_MUTED);
156 time = transit->fade_in;
158 pa_log_debug(" attenuation 0 dB "
159 "transition time %ld ms", time);
160 set_stream_volume_limit(u, sinp, PA_VOLUME_NORM, time);
164 dB = mir_volume_apply_limits(u, device_node, mask, class, stamp);
165 newvol = pa_sw_volume_from_dB(dB);
169 oldvol = ramp->ramps[0].target;
172 time = transit->fade_out;
173 else if (oldvol < newvol)
174 time = transit->fade_in;
179 oldvol = sinp->volume_factor.values[0];
183 if (oldvol == newvol)
184 pa_log_debug(" attenuation %.2lf dB",dB);
186 pa_log_debug(" attenuation %.2lf dB "
187 "transition time %ld ms", dB, time);
188 set_stream_volume_limit(u, sinp, newvol, time);
191 } /* PA_IDXSET_FOREACH sinp */
193 } /* PA_IDXSET_FOREACH sink */
196 void pa_fader_ramp_volume(struct userdata *u,
200 transition_time *transit;
203 pa_cvolume_ramp_int *ramp;
205 pa_cvolume_ramp rampvol;
211 transit = &u->fader->transit;
212 rampit = transit->fade_in > 0 && transit->fade_out > 0;
214 oldvol = ramp->ramps[0].target;
216 if (rampit && oldvol != newvol) {
217 time = (oldvol > newvol) ? transit->fade_out : transit->fade_in;
219 pa_cvolume_ramp_set(&rampvol,
220 sinp->volume.channels,
221 PA_VOLUME_RAMP_TYPE_LINEAR,
224 pa_sink_input_set_volume_ramp(sinp, &rampvol, true, false);
229 void pa_fader_set_volume(struct userdata *u,
234 pa_cvolume_ramp_int *ramp;
235 pa_cvolume_ramp rampvol;
241 oldvol = ramp->ramps[0].target;
243 if (oldvol != newvol) {
244 pa_cvolume_ramp_set(&rampvol,
245 sinp->volume.channels,
246 PA_VOLUME_RAMP_TYPE_LINEAR,
249 pa_sink_input_set_volume_ramp(sinp, &rampvol, true, false);
253 pa_volume_t pa_fader_get_volume(struct userdata *u, pa_sink_input *sinp)
255 pa_cvolume_ramp_int *ramp;
262 vol = ramp->ramps[0].target;
267 static void set_stream_volume_limit(struct userdata *u,
273 pa_cvolume_ramp rampvol;
277 pa_assert_se((sink = sinp->sink));
280 pa_cvolume_set(&sinp->volume_factor, sinp->volume.channels, vol);
282 if (pa_sink_flat_volume_enabled(sink)) {
283 pa_sink_set_volume(sink, NULL, true, false);
286 pa_sw_cvolume_multiply(&sinp->soft_volume, &sinp->real_ratio,
287 &sinp->volume_factor);
289 pa_asyncmsgq_send(sink->asyncmsgq, PA_MSGOBJECT(sinp),
290 PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME,
295 pa_cvolume_ramp_set(&rampvol,
296 sinp->volume.channels,
297 PA_VOLUME_RAMP_TYPE_LINEAR,
301 pa_sink_input_set_volume_ramp(sinp, &rampvol, true, false);
309 * indent-tabs-mode: nil