6b29d8d6a172e403403d78d1de4edc0f116c2011
[staging/agl-audio-plugin.git] / utils.c
1 /*
2  * module-agl-audio -- PulseAudio module for providing audio routing support
3  * (forked from "module-murphy-ivi" - https://github.com/otcshare )
4  * Copyright (c) 2012, Intel Corporation.
5  * Copyright (c) 2016, IoT.bzh
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms and conditions of the GNU Lesser General Public License,
9  * version 2.1, as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
19  * MA 02110-1301 USA.
20  *
21  */
22 #include "userdata.h"
23 #include "utils.h"
24 #include "node.h"
25
26 #define DEFAULT_NULL_SINK_NAME "null.agl"
27
28 #ifndef PA_PROP_PROCESS_ENVIRONMENT
29 #define PA_PROP_PROCESS_ENVIRONMENT "application.process.environment"
30 #endif
31 #define PA_ZONE_NAME_DEFAULT "driver"
32 #define PA_PROP_ZONE_NAME "zone.name"
33 #define PA_PROP_ENV_ZONE  PA_PROP_PROCESS_ENVIRONMENT ".AUDIO_ZONE"
34
35 #define PA_PROP_ROUTING_CLASS_NAME "routing.class.name"
36 #define PA_PROP_ROUTING_CLASS_ID   "routing.class.id"
37 #define PA_PROP_ROUTING_METHOD     "routing.method"
38
39 static uint32_t stamp;
40
41 struct agl_null_sink {
42         char      *name;
43         uint32_t   module_index;
44         uint32_t   sink_index;
45 };
46
47 agl_null_sink *agl_utils_create_null_sink (struct userdata *u, const char *name)
48 {
49         pa_core      *core;
50         pa_module    *module;
51         pa_sink      *s, *sink;
52         agl_null_sink *ns;
53         uint32_t      idx;
54         char          args[256];
55
56         pa_assert (u);
57         pa_assert_se (core = u->core);
58
59         if (!name)
60                 name = DEFAULT_NULL_SINK_NAME;  /* default is "null.agl" */
61
62         snprintf (args, sizeof(args), "sink_name=\"%s.%d\" channels=2", name, agl_utils_new_stamp ());
63         module = pa_module_load (core, "module-null-sink", args);
64         sink = NULL;
65
66         if (!module) {
67                 pa_log ("failed to load null sink '%s'", name);
68                 return NULL;
69         } else {
70                 PA_IDXSET_FOREACH(s, core->sinks, idx) {
71                         if (s->module && s->module == module) {
72                                 sink = s;
73                                 pa_log_info("created agl null sink named '%s'", name);
74                                 break;
75                         }
76                 }
77         }
78
79         ns = pa_xnew0 (agl_null_sink, 1);
80         ns->name = pa_xstrdup (name);
81         ns->module_index = module ? module->index : PA_IDXSET_INVALID;
82         ns->sink_index = sink ? sink->index : PA_IDXSET_INVALID;
83
84         return ns;
85 }
86
87 void agl_utils_destroy_null_sink (struct userdata *u, agl_null_sink *ns)
88 {
89         pa_core      *core;
90         pa_module    *module;
91
92         if (u && (core = u->core)) {
93                 if ((module = pa_idxset_get_by_index (core->modules, ns->module_index))){
94                         pa_log_info ("unloading null sink '%s'", ns->name);
95                         pa_module_unload (module, false);
96                 }
97
98                 pa_xfree (ns->name);
99                 pa_xfree (ns);
100         }
101 }
102
103 pa_sink *agl_utils_get_null_sink (struct userdata *u, struct agl_null_sink *ns)
104 {
105         pa_core *core;
106         pa_sink *sink;
107
108         pa_assert (u);
109         pa_assert_se ((core = u->core));
110
111         return pa_idxset_get_by_index (core->sinks, ns->sink_index);
112 }
113
114 pa_source *agl_utils_get_null_source (struct userdata *u, struct agl_null_sink *ns)
115 {
116         pa_sink *sink;
117
118         sink = agl_utils_get_null_sink (u, ns);
119
120         return sink ? sink->monitor_source : NULL;
121 }
122
123 void agl_utils_volume_ramp (struct userdata *u, struct agl_null_sink *ns, bool up)
124 {
125         pa_core *core;
126         pa_sink *sink;
127         pa_sink_input *sinp;
128         uint32_t index;
129         pa_cvolume_ramp rampvol;
130         pa_volume_t newvol;
131         long time;
132
133         if (up) {
134                 newvol = PA_VOLUME_NORM;
135                 time = 5000;
136         } else {
137                 newvol = PA_VOLUME_NORM *10/100;
138                 time = 3000;
139         }
140
141         pa_assert (u);
142         pa_assert_se ((core = u->core));
143
144         sink = agl_utils_get_null_sink (u, ns);
145         PA_IDXSET_FOREACH(sinp, core->sink_inputs, index) {
146                 if (sinp->sink && sinp->sink == sink)
147                         break;
148                 sinp = NULL;
149         }
150         if (!sinp) return;
151
152         pa_cvolume_ramp_set (&rampvol, sinp->volume.channels, PA_VOLUME_RAMP_TYPE_LINEAR,
153                              time, newvol);
154         pa_sink_input_set_volume_ramp (sinp, &rampvol, true, false);
155 }
156
157 const char *agl_utils_get_card_name (pa_card *card)
158 {
159         return (card && card->name) ? card->name : "<unknown>";
160 }
161
162 const char *agl_utils_get_card_bus (pa_card *card)
163 {
164         const char *bus = NULL;
165         const char *name;
166
167         if (card && !(bus = pa_proplist_gets (card->proplist,PA_PROP_DEVICE_BUS))) {
168                 name = agl_utils_get_card_name (card);
169                 if (!strncmp (name, "alsa_card.", 10)) {
170                         if (!strncmp (name + 10, "pci-", 4))
171                                 bus = "pci";
172                         else if (!strncmp (name + 10, "platform-", 9))
173                                 bus = "platform";
174                         else if (!strncmp (name + 10, "usb-", 4))
175                                 bus = "usb";
176                 }
177         }
178
179         return (char *)bus;
180 }
181
182 const char *agl_utils_get_sink_name (pa_sink *sink)
183 {
184         return (sink && sink->name) ? sink->name : "<unknown>";
185 }
186
187 const char *agl_utils_get_source_name (pa_source *source)
188 {
189         return (source && source->name) ? source->name : "<unknown>";
190 }
191
192 const char *agl_utils_get_sink_input_name (pa_sink_input *sinp)
193 {
194         char *name = NULL;
195
196         if (sinp && sinp->proplist) {
197                 name = (char *)pa_proplist_gets (sinp->proplist, PA_PROP_APPLICATION_NAME);
198                 if (!name)
199                         name = (char *)pa_proplist_gets (sinp->proplist, PA_PROP_APPLICATION_PROCESS_BINARY);
200                 if (!name)
201                         name = "<unknown>";
202         }
203
204         return (const char *)name;
205 }
206
207 const char *agl_utils_get_source_output_name (pa_source_output *sout)
208 {
209         char *name = NULL;
210
211         if (sout && sout->proplist) {
212                 name = (char *)pa_proplist_gets (sout->proplist, PA_PROP_APPLICATION_NAME);
213                 if (!name)
214                         name = (char *)pa_proplist_gets (sout->proplist, PA_PROP_APPLICATION_PROCESS_BINARY);
215                 if (!name)
216                         name = "<unknown>";
217         }
218
219         return (const char *)name;
220 }
221
222 pa_sink *agl_utils_get_primary_alsa_sink (struct userdata *u)
223 {
224         pa_core *core;
225         pa_sink *sink;
226         uint32_t idx;
227
228         pa_assert (u);
229         pa_assert_se ((core = u->core));
230
231         PA_IDXSET_FOREACH(sink, core->sinks, idx) {
232                 if (sink->name && strstr (sink->name, "alsa_output"))
233                         return sink;
234         }
235
236         return NULL;
237 }
238
239 pa_sink *agl_utils_get_alsa_sink (struct userdata *u, const char *name)
240 {
241         pa_core *core;
242         pa_sink *sink;
243         uint32_t idx;
244
245         pa_assert (u);
246         pa_assert_se ((core = u->core));
247
248         PA_IDXSET_FOREACH(sink, core->sinks, idx) {
249                 if (sink->name && strstr (sink->name, "alsa_output")
250                                && strstr (sink->name, name))
251                                 return sink;
252         }
253
254         return NULL;
255 }
256
257 void agl_utils_init_stamp (void)
258 {
259         stamp = 0;
260 }
261
262 uint32_t agl_utils_new_stamp (void)
263 {
264         return ++stamp;
265 }
266
267 uint32_t agl_utils_get_stamp (void)
268 {
269         return stamp;
270 }
271
272
273
274 char *agl_utils_get_zone (pa_proplist *pl, pa_proplist *client_props)
275 {
276         const char *zone;
277
278         pa_assert (pl);
279
280          /* grab the "zone.name" PA_PROP environment variable ;
281           * otherwise just fall back to default "driver" zone */
282         zone = pa_proplist_gets (pl, PA_PROP_ZONE_NAME);
283         if (!zone) {
284                 if (!client_props || !(zone = pa_proplist_gets (client_props, PA_PROP_ENV_ZONE)))
285                         zone = PA_ZONE_NAME_DEFAULT;            
286         }
287
288         return (char *)zone;
289 }
290
291 bool agl_utils_set_stream_routing_properties (pa_proplist *pl, int styp, void *target)
292 {
293         const char *clnam;      /* will become "agl_player" e.g. */
294         char clid[32];          /* will become "1" e.g. */
295         const char *method;     /* will become "default" (it target is NULL) or "explicit" */
296
297         pa_assert (pl);
298         pa_assert (styp >= 0);  /* type different from "agl_node_type_unknown" */
299
300         clnam = agl_node_type_str (styp);
301         snprintf (clid, sizeof(clid), "%d", styp);
302         method = target ? "explicit" : "default";
303
304         if (pa_proplist_sets (pl, PA_PROP_ROUTING_CLASS_NAME, clnam ) < 0 ||
305             pa_proplist_sets (pl, PA_PROP_ROUTING_CLASS_ID  , clid  ) < 0 ||
306             pa_proplist_sets (pl, PA_PROP_ROUTING_METHOD    , method) < 0)
307         {
308                 pa_log ("failed to set some stream property");
309                 return false;
310         }
311
312         return true;
313 }
314
315 bool agl_utils_unset_stream_routing_properties (pa_proplist *pl)
316 {
317         pa_assert (pl);
318
319         if (pa_proplist_unset (pl, PA_PROP_ROUTING_CLASS_NAME) < 0 ||
320             pa_proplist_unset (pl, PA_PROP_ROUTING_CLASS_ID  ) < 0 ||
321             pa_proplist_unset (pl, PA_PROP_ROUTING_METHOD    ) < 0)
322         {
323                 pa_log ("failed to unset some stream property");
324                 return false;
325         }
326
327         return true;    
328 }