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/module.h>
36 #define VLIM_CLASS_ALLOC_BUCKET 16
38 typedef struct vlim_entry vlim_entry;
39 typedef struct vlim_table vlim_table;
43 mir_volume_func_t func; /**< volume limit function */
44 void *arg; /**< arg given at registration time */
52 struct pa_mir_volume {
53 int classlen; /**< class table length */
54 vlim_table *classlim; /**< class indexed table */
55 vlim_table genlim; /**< generic limit */
59 static void add_to_table(vlim_table *, mir_volume_func_t, void *);
60 static void destroy_table(vlim_table *);
61 static double apply_table(double, vlim_table *, struct userdata *, int,
62 mir_node *, const char *);
64 static void reset_volume_limit(struct userdata *, mir_node *, uint32_t);
65 static void add_volume_limit(struct userdata *, mir_node *, int);
68 pa_mir_volume *pa_mir_volume_init(struct userdata *u)
70 pa_mir_volume *volume = pa_xnew0(pa_mir_volume, 1);
77 void pa_mir_volume_done(struct userdata *u)
79 pa_mir_volume *volume;
82 if (u && (volume = u->volume)) {
83 for (i = 0; i < volume->classlen; i++) {
84 destroy_table(volume->classlim + i);
86 free(volume->classlim);
88 destroy_table(&volume->genlim);
96 void mir_volume_add_class_limit(struct userdata *u,
98 mir_volume_func_t func,
101 pa_mir_volume *volume;
102 vlim_table *classlim;
110 pa_assert(class > 0);
111 pa_assert_se((volume = u->volume));
113 if (class < volume->classlen)
114 table = volume->classlim + class;
117 size = sizeof(vlim_table) * newlen;
118 diff = sizeof(vlim_table) * (newlen - volume->classlen);
120 pa_assert_se((classlim = realloc(volume->classlim, size)));
121 memset(classlim + volume->classlen, 0, diff);
124 volume->classlen = newlen;
125 volume->classlim = classlim;
127 table = classlim + class;
130 add_to_table(table, func, arg);
134 void mir_volume_add_generic_limit(struct userdata *u,
135 mir_volume_func_t func,
138 pa_mir_volume *volume;
142 pa_assert_se((volume = u->volume));
144 add_to_table(&volume->genlim, func, arg);
148 void mir_volume_make_limiting(struct userdata *u)
154 stamp = pa_utils_new_stamp();
156 pa_fader_apply_volume_limits(u, stamp);
159 void mir_volume_add_limiting_class(struct userdata *u,
166 pa_assert(class >= 0);
168 if (node->implement == mir_device && node->direction == mir_output) {
169 if (stamp > node->vlim.stamp)
170 reset_volume_limit(u, node, stamp);
172 add_volume_limit(u, node, class);
177 double mir_volume_apply_limits(struct userdata *u,
182 pa_mir_volume *volume;
183 double attenuation = 0.0;
184 double devlim, classlim;
189 pa_assert_se((volume = u->volume));
191 if (class < 0 || class >= volume->classlen) {
192 if (class < 0 || class >= mir_application_class_end)
196 devlim = apply_table(0.0, &volume->genlim, u,class,node, "device");
200 pa_assert(class >= mir_application_class_begin);
201 pa_assert(class < mir_application_class_end);
203 clmask = (uint32_t)1 << (class - mir_application_class_begin);
205 if (class < volume->classlen && (tbl = volume->classlim + class))
206 classlim = apply_table(classlim, tbl, u, class, node, "class");
209 attenuation = devlim + classlim;
216 double mir_volume_suppress(struct userdata *u, int class, mir_node *node,
219 mir_volume_suppress_arg *suppress = arg;
220 uint32_t clmask, trigmask;
223 pa_assert(class >= mir_application_class_begin);
224 pa_assert(class < mir_application_class_end);
226 pa_assert(node->direction == mir_output);
227 pa_assert(node->implement == mir_device);
229 clmask = ((uint32_t)1) << (class - mir_application_class_begin);
231 if (suppress && (trigmask = suppress->trigger.clmask)) {
232 pa_log_debug(" volume_supress(class=%d, clmask=0x%x, "
233 "trigmask=0x%x nodemask=0x%x)",
234 class, clmask, trigmask, node->vlim.clmask);
236 if (!(trigmask & clmask) && (trigmask & node->vlim.clmask))
237 return *suppress->attenuation;
243 double mir_volume_correction(struct userdata *u, int class, mir_node *node,
249 if (arg && *(double **)arg &&
250 node->implement == mir_device &&
251 node->privacy == mir_public)
253 return **(double **)arg;
259 static void add_to_table(vlim_table *tbl, mir_volume_func_t func, void *arg)
268 size = sizeof(vlim_entry) * (tbl->nentry + 1);
269 pa_assert_se((entries = realloc(tbl->entries, size)));
270 entry = entries + tbl->nentry;
276 tbl->entries = entries;
279 static void destroy_table(vlim_table *tbl)
286 static double apply_table(double attenuation,
293 static mir_node fake_node;
306 for (i = 0; i < tbl->nentry; i++) {
307 e = tbl->entries + i;
308 a = e->func(u, class, node, e->arg);
310 pa_log_debug(" %s limit = %.2lf", type, a);
321 static void reset_volume_limit(struct userdata *u,
325 mir_vlim *vlim = &node->vlim;
334 pa_assert_se((core = u->core));
336 pa_log_debug("reset volume classes on node '%s'", node->amname);
342 if ((sink = pa_idxset_get_by_index(core->sinks, node->paidx))) {
343 PA_IDXSET_FOREACH(sinp, sink->inputs, i) {
344 class = pa_utils_get_stream_class(sinp->proplist);
345 add_volume_limit(u, node, class);
351 static void add_volume_limit(struct userdata *u, mir_node *node, int class)
353 mir_vlim *vlim = &node->vlim;
354 pa_mir_volume *volume;
361 pa_assert_se((volume = u->volume));
362 pa_assert(class >= 0);
364 if (class < mir_application_class_begin ||
365 class >= mir_application_class_end )
367 pa_log_debug("refusing to add unknown volume class %d to node '%s'",
368 class, node->amname);
371 mask = ((uint32_t)1) << (class - mir_application_class_begin);
373 if (class < volume->classlen && volume->classlim[class].nentry > 0) {
374 if (!(vlim->clmask & mask)) {
376 if (vlim->nclass < vlim->maxentry)
377 classes = vlim->classes;
379 vlim->maxentry += VLIM_CLASS_ALLOC_BUCKET;
380 classes_size = sizeof(int *) * vlim->maxentry;
381 vlim->classes = realloc(vlim->classes, classes_size);
383 pa_assert_se((classes = vlim->classes));
386 vlim->classes[vlim->nclass++] = class;
390 if (!(vlim->clmask & mask)) {
391 pa_log_debug("add volume class %d (%s) to node '%s' (clmask 0x%x)",
392 class, mir_node_type_str(class), node->amname,
396 vlim->clmask |= mask;
407 * indent-tabs-mode: nil