build: fix unused/unset variables and other compilation warnings
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / volume.c
1 /*
2  * module-murphy-ivi -- PulseAudio module for providing audio routing support
3  * Copyright (c) 2012, Intel Corporation.
4  *
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.
8  *
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.
13  *
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,
17  * MA 02110-1301 USA.
18  *
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include <pulsecore/pulsecore-config.h>
26
27 #include <pulse/proplist.h>
28 #include <pulsecore/core-util.h>
29 #include <pulsecore/module.h>
30
31 #include "volume.h"
32 #include "node.h"
33
34 #define VLIM_CLASS_ALLOC_BUCKET  8
35
36 typedef struct vlim_entry  vlim_entry;
37 typedef struct vlim_table  vlim_table;
38
39
40 struct vlim_entry {
41     mir_volume_func_t func;      /**< volume limit function */
42     void             *arg;       /**< arg given at registration time */
43 };
44
45 struct vlim_table {
46     size_t       nentry;
47     vlim_entry  *entries;
48 };
49
50 struct pa_mir_volume {
51     int          classlen;   /**< class table length  */
52     vlim_table  *classlim;   /**< class indexed table */
53     vlim_table   genlim;     /**< generic limit */
54 };
55
56
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*);
60
61 static void reset_outdated_volume_limit(mir_vlim *, uint32_t);
62
63
64 pa_mir_volume *pa_mir_volume_init(struct userdata *u)
65 {
66     pa_mir_volume *volume = pa_xnew0(pa_mir_volume, 1);
67
68     (void)u;
69
70     return volume;
71 }
72
73 void pa_mir_volume_done(struct userdata *u)
74 {
75     pa_mir_volume *volume;
76     int i;
77
78     if (u && (volume = u->volume)) {
79         for (i = 0;   i < volume->classlen;   i++) {
80             destroy_table(volume->classlim + i);
81         }
82         free(volume->classlim);
83
84         destroy_table(&volume->genlim);
85
86         pa_xfree(volume);
87
88         u->volume = NULL;
89     }
90 }
91
92 void mir_volume_add_class_limit(struct userdata  *u,
93                                 int               class,
94                                 mir_volume_func_t func,
95                                 void             *arg)
96 {
97     pa_mir_volume *volume;
98     vlim_table    *classlim;
99     vlim_table    *table;
100     size_t         newlen;
101     size_t         size;
102     size_t         diff;
103
104     pa_assert(u);
105     pa_assert(func);
106     pa_assert(class > 0);
107     pa_assert_se((volume = u->volume));
108
109     if (class < volume->classlen)
110         table = volume->classlim + class;
111     else {
112         newlen = class + 1;
113         size = sizeof(vlim_table) * newlen;
114         diff = sizeof(vlim_table) * (newlen - volume->classlen);
115
116         pa_assert_se((classlim = realloc(volume->classlim, size)));
117         memset(classlim + volume->classlen, 0, diff);
118
119
120         volume->classlen = newlen;
121         volume->classlim = classlim;
122
123         table = classlim + class;
124     }
125
126     add_to_table(table, func, arg);
127 }
128
129
130 void mir_volume_add_generic_limit(struct userdata  *u,
131                                   mir_volume_func_t func,
132                                   void             *arg)
133 {
134     pa_mir_volume *volume;
135
136     pa_assert(u);
137     pa_assert(func);
138     pa_assert_se((volume = u->volume));
139
140     add_to_table(&volume->genlim, func, arg);
141 }
142
143 void mir_volume_add_limiting_class(struct userdata *u,
144                                    mir_node        *node,
145                                    int              class,
146                                    uint32_t         stamp)
147 {
148     pa_mir_volume *volume;
149     mir_vlim      *vlim;
150     int           *classes;
151     size_t         classes_size;
152     size_t         i;
153
154     pa_assert(u);
155     pa_assert(node);
156     pa_assert_se((volume = u->volume));
157     pa_assert(class >= 0);
158
159     if (node->implement == mir_device && node->direction == mir_output) {
160
161         vlim = &node->vlim;
162
163         reset_outdated_volume_limit(vlim, stamp);
164
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 */
169             }
170
171             pa_log_debug("add limiting class %d (%s) to node '%s'",
172                          class, mir_node_type_str(class), node->amname);
173
174             if (vlim->nclass < vlim->maxentry)
175                 classes = vlim->classes;
176             else {
177                 classes_size = sizeof(int *) * vlim->maxentry;
178
179                 vlim->maxentry += VLIM_CLASS_ALLOC_BUCKET;
180                 vlim->classes   = realloc(vlim->classes, classes_size);
181
182                 pa_assert_se((classes = vlim->classes));
183             }
184
185             vlim->classes[vlim->nclass++] = class;
186         }
187     }
188 }
189
190
191 double mir_volume_apply_limits(struct userdata *u,
192                                mir_node *node,
193                                int class,
194                                uint32_t stamp)
195 {
196     pa_mir_volume *volume;
197     mir_vlim *vlim;
198     double attenuation = 0.0;
199     vlim_table *tbl;
200     size_t i;
201     int c;
202
203     pa_assert(u);
204     pa_assert_se((volume = u->volume));
205
206     if (class < 0 || class >= volume->classlen) {
207         if (class < 0 || class >= mir_application_class_end)
208             attenuation = -90.0;
209     }
210     else {
211         /* generic limits */
212         attenuation = apply_table(attenuation, &volume->genlim, u,class,node); 
213
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];
218                 
219                 pa_assert(c >= 0 && c < volume->classlen);
220                 tbl = volume->classlim + c;
221                 
222                 attenuation = apply_table(attenuation, tbl, u, class, node);
223             }
224         }
225     }
226
227     return attenuation;
228 }
229                                
230
231 double mir_volume_suppress(struct userdata *u, int class, mir_node *node,
232                            void *arg)
233 {
234     mir_volume_suppress_arg *suppress = arg;
235     size_t i;
236
237     pa_assert(u);
238     pa_assert(node);
239
240     if (suppress) {
241         for (i = 0;   i < suppress->exception.nclass;   i++) {
242             if (suppress->exception.classes[i] == class)
243                 return 0.0;
244         }
245
246         return suppress->attenuation;
247     }
248
249     return 0.0;
250 }
251
252 double mir_volume_correction(struct userdata *u, int class, mir_node *node,
253                              void *arg)
254 {
255     pa_assert(u);
256     pa_assert(node);
257
258     if (arg && node->implement == mir_device && node->privacy == mir_public)
259         return *(double *)arg;
260
261     return 0.0;
262 }
263
264 static void add_to_table(vlim_table *tbl, mir_volume_func_t func, void *arg)
265 {
266     size_t      size;
267     vlim_entry *entries;
268     vlim_entry *entry;
269
270     pa_assert(tbl);
271     pa_assert(func);
272
273     size = sizeof(vlim_entry *) * (tbl->nentry + 1);
274     pa_assert_se((entries = realloc(tbl->entries,  size)));
275     entry = entries + tbl->nentry;
276
277     entry->func = func;
278     entry->arg  = arg;
279
280     tbl->nentry += 1;
281     tbl->entries = entries;
282 }
283
284 static void destroy_table(vlim_table *tbl)
285 {
286     pa_assert(tbl);
287     
288     free(tbl->entries);
289 }
290
291 static double apply_table(double attenuation,
292                           vlim_table *tbl,
293                           struct userdata *u,
294                           int class,
295                           mir_node *node)
296 {
297     static mir_node fake_node;
298
299     double a;
300     vlim_entry *e;
301     size_t i;
302
303     pa_assert(tbl);
304     pa_assert(u);
305
306     if (!node)
307         node = &fake_node;
308
309     for (i = 0;   i < tbl->nentry;  i++) {
310         e = tbl->entries + i;
311         if ((a = e->func(u, class, node, e->arg)) < attenuation)
312             attenuation = a;
313     }
314
315     return attenuation;
316 }
317
318
319
320 static void reset_outdated_volume_limit(mir_vlim *vl, uint32_t stamp)
321 {
322     if (stamp > vl->stamp) {
323         vl->nclass = 0;
324         vl->stamp  = stamp;
325     }
326 }
327
328
329
330
331
332 /*
333  * Local Variables:
334  * c-basic-offset: 4
335  * indent-tabs-mode: nil
336  * End:
337  *
338  */