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>
34 #define VLIM_CLASS_ALLOC_BUCKET 8
36 typedef struct vlim_entry vlim_entry;
37 typedef struct vlim_table vlim_table;
41 mir_volume_func_t func; /**< volume limit function */
42 void *arg; /**< arg given at registration time */
50 struct pa_mir_volume {
51 int classlen; /**< class table length */
52 vlim_table *classlim; /**< class indexed table */
53 vlim_table genlim; /**< generic limit */
57 static void add_to_table(vlim_table *, mir_volume_func_t, void *);
58 static void destroy_table(vlim_table *);
59 static double apply_table(double,vlim_table*, struct userdata *,int,mir_node*);
61 static void reset_outdated_volume_limit(mir_vlim *, uint32_t);
64 pa_mir_volume *pa_mir_volume_init(struct userdata *u)
66 pa_mir_volume *volume = pa_xnew0(pa_mir_volume, 1);
73 void pa_mir_volume_done(struct userdata *u)
75 pa_mir_volume *volume;
78 if (u && (volume = u->volume)) {
79 for (i = 0; i < volume->classlen; i++) {
80 destroy_table(volume->classlim + i);
82 free(volume->classlim);
84 destroy_table(&volume->genlim);
92 void mir_volume_add_class_limit(struct userdata *u,
94 mir_volume_func_t func,
97 pa_mir_volume *volume;
106 pa_assert(class > 0);
107 pa_assert_se((volume = u->volume));
109 if (class < volume->classlen)
110 table = volume->classlim + class;
113 size = sizeof(vlim_table) * newlen;
114 diff = sizeof(vlim_table) * (newlen - volume->classlen);
116 pa_assert_se((classlim = realloc(volume->classlim, size)));
117 memset(classlim + volume->classlen, 0, diff);
120 volume->classlen = newlen;
121 volume->classlim = classlim;
123 table = classlim + class;
126 add_to_table(table, func, arg);
130 void mir_volume_add_generic_limit(struct userdata *u,
131 mir_volume_func_t func,
134 pa_mir_volume *volume;
138 pa_assert_se((volume = u->volume));
140 add_to_table(&volume->genlim, func, arg);
143 void mir_volume_add_limiting_class(struct userdata *u,
148 pa_mir_volume *volume;
156 pa_assert_se((volume = u->volume));
157 pa_assert(class >= 0);
159 if (node->implement == mir_device && node->direction == mir_output) {
163 reset_outdated_volume_limit(vlim, stamp);
165 if (class < volume->classlen && volume->classlim[class].nentry > 0) {
166 for (i = 0; i < vlim->nclass; i++) {
167 if (class == vlim->classes[i])
168 return; /* it is already registered */
171 pa_log_debug("add limiting class %d (%s) to node '%s'",
172 class, mir_node_type_str(class), node->amname);
174 if (vlim->nclass < vlim->maxentry)
175 classes = vlim->classes;
177 classes_size = sizeof(int *) * vlim->maxentry;
179 vlim->maxentry += VLIM_CLASS_ALLOC_BUCKET;
180 vlim->classes = realloc(vlim->classes, classes_size);
182 pa_assert_se((classes = vlim->classes));
185 vlim->classes[vlim->nclass++] = class;
191 double mir_volume_apply_limits(struct userdata *u,
196 pa_mir_volume *volume;
198 double attenuation = 0.0;
204 pa_assert_se((volume = u->volume));
206 if (class < 0 || class >= volume->classlen) {
207 if (class < 0 || class >= mir_application_class_end)
212 attenuation = apply_table(attenuation, &volume->genlim, u,class,node);
214 /* class-based limits */
215 if (node && (vlim = &node->vlim) && stamp <= vlim->stamp) {
216 for (i = 0; i < vlim->nclass; i++) {
217 c = vlim->classes[i];
219 pa_assert(c >= 0 && c < volume->classlen);
220 tbl = volume->classlim + c;
222 attenuation = apply_table(attenuation, tbl, u, class, node);
231 double mir_volume_suppress(struct userdata *u, int class, mir_node *node,
234 mir_volume_suppress_arg *suppress = arg;
241 for (i = 0; i < suppress->exception.nclass; i++) {
242 if (suppress->exception.classes[i] == class)
246 return suppress->attenuation;
252 double mir_volume_correction(struct userdata *u, int class, mir_node *node,
258 if (arg && node->implement == mir_device && node->privacy == mir_public)
259 return *(double *)arg;
264 static void add_to_table(vlim_table *tbl, mir_volume_func_t func, void *arg)
273 size = sizeof(vlim_entry *) * (tbl->nentry + 1);
274 pa_assert_se((entries = realloc(tbl->entries, size)));
275 entry = entries + tbl->nentry;
281 tbl->entries = entries;
284 static void destroy_table(vlim_table *tbl)
291 static double apply_table(double attenuation,
297 static mir_node fake_node;
309 for (i = 0; i < tbl->nentry; i++) {
310 e = tbl->entries + i;
311 if ((a = e->func(u, class, node, e->arg)) < attenuation)
320 static void reset_outdated_volume_limit(mir_vlim *vl, uint32_t stamp)
322 if (stamp > vl->stamp) {
335 * indent-tabs-mode: nil