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 (origin == NULL) {
122 pa_log_debug("could not find origin for sink-input %d", sinp->index);
124 else if ((class = pa_utils_get_stream_class(sinp->proplist)) > 0) {
126 corked = stream_node ? !stream_node->rset.grant : false;
127 muted = (sinp->muted || pa_hashmap_get(sinp->volume_factor_items,
129 if (origin != sinp) {
130 muted |= (origin->muted || pa_hashmap_get(origin->volume_factor_items,
134 if (!corked && !muted)
135 mask |= mir_volume_get_class_mask(class);
137 pa_log_debug("*** stream %u (origin %u) class: %d corked: %s muted: %s "
138 "(sinp:%s internal:%s)", sinp->index, origin->index,
139 class, corked?"yes":"no ",
140 muted?"yes":"no", sinp->muted ? "yes":"no",
141 pa_hashmap_get(sinp->volume_factor_items,"internal_mute")?"yes":"no");
144 pa_log_debug("*** steam %u (origin %u) class: %d", sinp->index, origin->index, class);
147 pa_log_debug("*** mask: 0x%x", mask);
149 PA_IDXSET_FOREACH(sinp, sink->inputs, j) {
150 class = pa_utils_get_stream_class(sinp->proplist);
152 pa_log_debug(" stream %u (class %u)", sinp->index, class);
155 if (!(sinp->flags & PA_SINK_INPUT_START_RAMP_MUTED))
156 pa_log_debug(" skipping");
158 sinp->flags &= ~((unsigned int)PA_SINK_INPUT_START_RAMP_MUTED);
159 time = transit->fade_in;
161 pa_log_debug(" attenuation 0 dB "
162 "transition time %ld ms", time);
163 set_stream_volume_limit(u, sinp, PA_VOLUME_NORM, time);
167 dB = mir_volume_apply_limits(u, device_node, mask, class, stamp);
168 newvol = pa_sw_volume_from_dB(dB);
172 oldvol = ramp->ramps[0].target;
175 time = transit->fade_out;
176 else if (oldvol < newvol)
177 time = transit->fade_in;
182 oldvol = sinp->volume_factor.values[0];
186 if (oldvol == newvol)
187 pa_log_debug(" attenuation %.2lf dB",dB);
189 pa_log_debug(" attenuation %.2lf dB "
190 "transition time %ld ms", dB, time);
191 set_stream_volume_limit(u, sinp, newvol, time);
194 } /* PA_IDXSET_FOREACH sinp */
196 } /* PA_IDXSET_FOREACH sink */
199 void pa_fader_ramp_volume(struct userdata *u,
203 transition_time *transit;
206 pa_cvolume_ramp_int *ramp;
208 pa_cvolume_ramp rampvol;
214 transit = &u->fader->transit;
215 rampit = transit->fade_in > 0 && transit->fade_out > 0;
217 oldvol = ramp->ramps[0].target;
219 if (rampit && oldvol != newvol) {
220 time = (oldvol > newvol) ? transit->fade_out : transit->fade_in;
222 pa_cvolume_ramp_set(&rampvol,
223 sinp->volume.channels,
224 PA_VOLUME_RAMP_TYPE_LINEAR,
227 pa_sink_input_set_volume_ramp(sinp, &rampvol, true, false);
232 void pa_fader_set_volume(struct userdata *u,
237 pa_cvolume_ramp_int *ramp;
238 pa_cvolume_ramp rampvol;
244 oldvol = ramp->ramps[0].target;
246 if (oldvol != newvol) {
247 pa_cvolume_ramp_set(&rampvol,
248 sinp->volume.channels,
249 PA_VOLUME_RAMP_TYPE_LINEAR,
252 pa_sink_input_set_volume_ramp(sinp, &rampvol, true, false);
256 pa_volume_t pa_fader_get_volume(struct userdata *u, pa_sink_input *sinp)
258 pa_cvolume_ramp_int *ramp;
265 vol = ramp->ramps[0].target;
270 static void set_stream_volume_limit(struct userdata *u,
276 pa_cvolume_ramp rampvol;
280 pa_assert_se((sink = sinp->sink));
283 pa_cvolume_set(&sinp->volume_factor, sinp->volume.channels, vol);
285 if (pa_sink_flat_volume_enabled(sink)) {
286 pa_sink_set_volume(sink, NULL, true, false);
289 pa_sw_cvolume_multiply(&sinp->soft_volume, &sinp->real_ratio,
290 &sinp->volume_factor);
292 pa_asyncmsgq_send(sink->asyncmsgq, PA_MSGOBJECT(sinp),
293 PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME,
298 pa_cvolume_ramp_set(&rampvol,
299 sinp->volume.channels,
300 PA_VOLUME_RAMP_TYPE_LINEAR,
304 pa_sink_input_set_volume_ramp(sinp, &rampvol, true, false);
312 * indent-tabs-mode: nil