stream-manager: Update filter parameters to filter_info structure and to each stream...
[platform/core/multimedia/pulseaudio-modules-tizen.git] / src / stream-manager-filter.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2017 KimJeongYeon <jeongyeon.kim@samsung.com>
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include "stream-manager-priv.h"
27 #include "stream-manager-filter-priv.h"
28
29 #define MODULE_FILTER_APPLY             "module-filter-apply"
30 #define PA_PROP_FILTER_APPLY_GROUP      PA_PROP_FILTER_APPLY".%s.group"
31 #define PA_PROP_FILTER_APPLY_PARAMETERS PA_PROP_FILTER_APPLY".%s.parameters"
32
33 /* Based on parse_control_parameters() of module-ladspa-sink.c */
34 static int32_t parse_filter_control_parameters(const char *cdata, double *read_values, bool *use_default,
35                                                const uint32_t max_n_control) {
36     uint32_t p = 0;
37     const char *state = NULL;
38     char *k;
39
40     pa_assert(read_values);
41     pa_assert(use_default);
42
43     pa_log_debug("Trying to read control values");
44
45     if (!cdata)
46         return -1;
47
48     pa_log_debug("cdata: '%s'", cdata);
49
50     while ((k = pa_split(cdata, ",", &state)) && p < max_n_control) {
51         double f;
52
53         if (*k == 0) {
54             pa_log_debug("Read empty control value (p=%d)", p);
55             use_default[p++] = true;
56             pa_xfree(k);
57             continue;
58         }
59
60         if (pa_atod(k, &f) < 0) {
61             pa_log_debug("Failed to parse control value '%s' (p=%d)", k, p);
62             pa_xfree(k);
63             goto fail;
64         }
65
66         pa_xfree(k);
67
68         pa_log_debug("Read control value %f (p=%d)", f, p);
69
70         use_default[p] = false;
71         read_values[p++] = f;
72     }
73
74     /* The previous loop doesn't take the last control value into account
75      * if it is left empty, so we do it here. */
76     if (*cdata == 0 || cdata[strlen(cdata) - 1] == ',') {
77         if (p < max_n_control)
78             use_default[p] = true;
79         p++;
80     }
81
82     if (p > max_n_control || k) {
83         pa_log("Too many control values passed, %d expected.", max_n_control);
84         pa_xfree(k);
85         goto fail;
86     }
87
88     /* Return number of controls */
89     return (int32_t)p;
90
91 fail:
92     return -1;
93 }
94
95 /* Set property to ladspa-sink */
96 static int32_t control_filter_ladspa(DBusConnection *conn, filter_info *f, uint32_t s_idx) {
97     DBusMessage *msg = NULL;
98     DBusError err;
99     DBusMessageIter msg_iter, variant_iter, struct_iter;
100     uint32_t i;
101     double *control = NULL;
102     dbus_bool_t *use_default = NULL;
103     int ret;
104     char *ladspa_object_path;
105     const char *ladspa_interface = "org.PulseAudio.Ext.Ladspa1";
106     const char *ladspa_propname = "AlgorithmParameters";
107
108     pa_assert(conn);
109     pa_assert(f);
110
111     dbus_error_init(&err);
112
113     ladspa_object_path = pa_sprintf_malloc("/org/pulseaudio/core1/sink%d", s_idx);
114
115     if (!(msg = dbus_message_new_method_call("org.pulseaudio.Server",
116                                              ladspa_object_path,
117                                              "org.freedesktop.DBus.Properties",
118                                              "Set"))) {
119         pa_log_error("failed dbus method call");
120         ret = -1;
121         goto finish;
122     }
123
124     dbus_message_iter_init_append(msg, &msg_iter);
125
126     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &ladspa_interface);
127     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &ladspa_propname);
128
129     /* Variant has struct of two arrays, signature : (adab) */
130     dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_VARIANT, "(adab)", &variant_iter);
131     dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter);
132
133     /* Copying because of the D-Bus type mapping */
134     control = pa_xnew(double, f->n_controls);
135     use_default = pa_xnew(dbus_bool_t, f->n_controls);
136
137     for (i = 0; i < f->n_controls; i++) {
138         control[i] = f->controls.values[i];
139         use_default[i] = (dbus_bool_t)f->controls.use_default[i];
140     }
141
142     pa_dbus_append_basic_array(&struct_iter, DBUS_TYPE_DOUBLE, control, f->n_controls);
143     pa_dbus_append_basic_array(&struct_iter, DBUS_TYPE_BOOLEAN, use_default, f->n_controls);
144
145     dbus_message_iter_close_container(&variant_iter, &struct_iter);
146     dbus_message_iter_close_container(&msg_iter, &variant_iter);
147
148     dbus_message_set_no_reply(msg, true);
149     if (!dbus_connection_send(conn, msg, NULL)) {
150         pa_log_error("Failed to method call org.freedesktop.DBus.Properties.Set, %s", err.message);
151         ret = -1;
152         goto finish;
153     }
154
155     ret = 0;
156
157 finish:
158     if (msg)
159         dbus_message_unref(msg);
160     dbus_error_free(&err);
161
162     pa_xfree(control);
163     pa_xfree(use_default);
164     pa_xfree(ladspa_object_path);
165
166     return ret;
167 }
168
169 static void update_prop_filter_apply_group(pa_sink_input *si, filter_info *f, const char *filter_apply) {
170     char *prop_group = NULL;
171
172     pa_assert(si);
173     pa_assert(filter_apply);
174
175     prop_group = pa_sprintf_malloc(PA_PROP_FILTER_APPLY_GROUP, filter_apply);
176
177     if (!f)
178         pa_proplist_unset(si->proplist, prop_group);
179     else if (f->group)
180         pa_proplist_sets(si->proplist, prop_group, f->group);
181
182     pa_xfree(prop_group);
183 }
184
185 static void update_prop_filter_apply_params(pa_sink_input *si, filter_info *f, const char *filter_apply) {
186     char *prop_parameters = NULL;
187
188     pa_assert(si);
189     pa_assert(filter_apply);
190
191     prop_parameters = pa_sprintf_malloc(PA_PROP_FILTER_APPLY_PARAMETERS, filter_apply);
192
193     if (!f)
194         pa_proplist_unset(si->proplist, prop_parameters);
195     else if (f->parameters)
196         pa_proplist_sets(si->proplist, prop_parameters, f->parameters);
197
198     pa_xfree(prop_parameters);
199 }
200
201 /* Invoked from dbus method call or hook fire */
202 int32_t apply_filter_to_sink_input(pa_sink_input *si, filter_info *f, bool need_to_hook) {
203     pa_assert(si);
204
205     if (f && (!f->filter_apply || pa_streq(f->filter_apply, ""))) {
206         pa_log_error("Try to applying empty filter module");
207         return -1;
208     }
209
210     if (!f) {
211         const char *filter_apply = NULL;
212         /* Unload filter using module-filter-apply */
213         if ((filter_apply = pa_proplist_gets(si->proplist, PA_PROP_FILTER_APPLY))) {
214             update_prop_filter_apply_group(si, f, filter_apply);
215             update_prop_filter_apply_params(si, f, filter_apply);
216             pa_proplist_unset(si->proplist, PA_PROP_FILTER_APPLY);
217         }
218     } else {
219         /* Load filter using module-filter-apply */
220         pa_proplist_sets(si->proplist, PA_PROP_FILTER_APPLY, f->filter_apply);
221         update_prop_filter_apply_group(si, f, f->filter_apply);
222         update_prop_filter_apply_params(si, f, f->filter_apply);
223     }
224
225     if (need_to_hook)
226         pa_hook_fire(&si->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], si);
227
228     return 0;
229 }
230
231 /* Invoked from dbus method call */
232 int32_t update_filter(pa_stream_manager *m, const char *filter_name, const char *filter_parameters, const char *filter_group,
233                       const char *stream_type) {
234     filter_info *f = NULL, *f_new = NULL;
235     uint32_t idx = 0;
236     pa_sink_input *si = NULL;
237     const char *role = NULL;
238     int32_t ret_apply = 0;
239     char *f_key;
240
241     if (pa_safe_streq(filter_name, "")) {
242         pa_log_error("Empty filter name");
243         return -1;
244     }
245
246     f = pa_hashmap_get(m->filter_infos, (const void*)stream_type);
247     if (f) {
248         pa_log_info("Remove existing filter_info[%p] of stream_type[%s]", f, stream_type);
249         pa_hashmap_remove_and_free(m->filter_infos, (const void*)stream_type);
250     }
251     if (filter_name) {
252         /* Add updated filter_info to hashmap */
253         f_key = pa_xstrdup(stream_type);
254         f_new = pa_xmalloc0(sizeof(filter_info));
255         f_new->filter_apply = pa_xstrdup(filter_name);
256         f_new->group = pa_xstrdup(filter_group);
257         f_new->parameters = pa_xstrdup(filter_parameters);
258         pa_hashmap_put(m->filter_infos, (void*)f_key, f_new);
259         pa_log_debug("Apply filter(module-%s) to streams of %s type", f_new->filter_apply, stream_type);
260     } else {
261         /* Remove filter_info from hashmap */
262         f_new = NULL;
263         pa_log_debug("Remove filter from streams of %s type", stream_type);
264     }
265
266     /* Apply or remove filter using module-filter-apply */
267     PA_IDXSET_FOREACH(si, m->core->sink_inputs, idx) {
268         role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE);
269         if (pa_safe_streq(role, stream_type)) {
270             if ((ret_apply = apply_filter_to_sink_input(si, f_new, true)) < 0) {
271                 pa_log_error("Failed to %s filter %s sink-input(%d)", f_new ? "apply" : "remove", f_new ? "to" : "from",
272                              si->index);
273                 return -1;
274             }
275         }
276     }
277
278     return 0;
279 }
280
281 #define MAX_ELEMENT_LENGTH 64
282 #define MAX_PARAMETERS_LENGTH 256
283 static void update_filter_parameters(filter_info *f) {
284     const char *split_state = NULL;
285     const char *control_element = "control=";
286     char *param_element = NULL;
287     char control_values[MAX_ELEMENT_LENGTH] = {'\0',};
288     char result_buf[MAX_PARAMETERS_LENGTH] = {'\0',};
289     uint32_t i;
290     int32_t len;
291     int32_t c_len;
292
293     pa_assert(f);
294
295     if (f->n_controls == 0)
296         return;
297
298     while ((param_element = pa_split(f->parameters, " ", &split_state))) {
299         len = strlen(result_buf);
300         if (!strncmp(param_element, control_element, strlen(control_element))) {
301             for (i = 0; i < f->n_controls; i++) {
302                 c_len = strlen(control_values);
303                 pa_snprintf(control_values + c_len, MAX_ELEMENT_LENGTH - c_len,
304                             (i == f->n_controls - 1) ? "%1.1f" : "%1.1f,", f->controls.values[i]);
305             }
306             pa_snprintf(result_buf + len, MAX_PARAMETERS_LENGTH - len, "%s%s", control_element, control_values);
307         } else {
308             pa_snprintf(result_buf + len, MAX_PARAMETERS_LENGTH - len, "%s ", param_element);
309         }
310         pa_xfree((void *)param_element);
311     }
312
313     pa_xfree((void *)f->parameters);
314     f->parameters = pa_xstrdup(result_buf);
315
316     pa_log_info("new filter parameters: %s", f->parameters);
317 }
318
319 /* Invoked from dbus method call */
320 int32_t control_filter(pa_stream_manager *m, const char *filter_name, const char *filter_controls, const char *stream_type,
321                        DBusConnection *conn) {
322     filter_info *f = NULL;
323     uint32_t si_idx = 0;
324     pa_sink_input *si = NULL;
325     const char *role = NULL;
326     uint32_t s_idx = 0;
327     pa_sink *s = NULL;
328
329     if (pa_streq(filter_name, "") || pa_streq(filter_controls, "")) {
330         pa_log_error("Empty filter name or controls");
331         return -1;
332     }
333
334     /* Search filter_info according to stream type, then get index of sink */
335     if (!(f = pa_hashmap_get(m->filter_infos, (const void*)stream_type))) {
336         pa_log_error("No filter information or sink to control");
337         return -1;
338     }
339
340     if (pa_safe_streq(f->filter_apply, filter_name)) {
341         PA_IDXSET_FOREACH(si, m->core->sink_inputs, si_idx) {
342             role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE);
343             if (pa_safe_streq(role, stream_type)) {
344                 s = si->sink;
345                 s_idx = s->index;
346                 break;
347             }
348         }
349     }
350
351     if (pa_safe_streq(f->filter_apply, "ladspa-sink") || (s && pa_safe_streq(s->module->name, "module-ladspa-sink"))) {
352         double read_values[FILTER_MAX_CONTROLS];
353         bool use_default[FILTER_MAX_CONTROLS];
354         int32_t n_controls;
355
356         /* Parse control parameters (e.g, "0.0, 0.1, 3.0") */
357         n_controls = parse_filter_control_parameters(filter_controls, read_values, use_default, FILTER_MAX_CONTROLS);
358         if (n_controls > 0) {
359             /* Save control parameters to filter_info */
360             uint32_t i;
361             for (i = 0; i < n_controls; i++) {
362                 f->controls.values[i] = read_values[i];
363                 f->controls.use_default[i] = use_default[i];
364                 f->n_controls = (uint32_t)n_controls;
365             }
366
367             /* update parameters */
368             update_filter_parameters(f);
369             if (s) {
370                 PA_IDXSET_FOREACH(si, m->core->sink_inputs, si_idx) {
371                     role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE);
372                     if (pa_safe_streq(role, stream_type))
373                         update_prop_filter_apply_params(si, f, f->filter_apply);
374                 }
375             }
376         } else {
377             pa_log_error("No filter controls to filter");
378             return -1;
379         }
380
381         /* Send control parameters to ladspa-sink */
382         if (s)
383             control_filter_ladspa(conn, f, s_idx);
384     } else {
385         pa_log_error("Sorry, it is able to control ladspa-sink only");
386         return -1;
387     }
388
389     return 0;
390 }
391
392 static pa_sink* get_master_sink_of_filter(pa_stream_manager *m, const char *filter_name, const char *filter_group) {
393     pa_sink_input *i;
394     pa_sink *master_sink;
395     uint32_t idx;
396     const char *role = NULL;
397     const char *filter_apply = NULL;
398
399     pa_assert(m);
400     pa_assert(filter_name);
401     pa_assert(filter_group);
402
403     /* We can not find sink_master directly only with module_name and stream_role,
404      * therefore, we use sink-input information instead of it */
405     PA_IDXSET_FOREACH(i, m->core->sink_inputs, idx) {
406         role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE);
407         filter_apply = pa_proplist_gets(i->proplist, PA_PROP_FILTER_APPLY);
408         if (pa_safe_streq(filter_name, filter_apply) && pa_safe_streq(role, filter_group)) {
409             if ((master_sink = pa_sink_get_master(i->sink))) {
410                 pa_log_info("Found master sink name[%s] of [module-%s, filter_group:%s]",
411                             master_sink->name, filter_name, filter_group);
412                 return master_sink;
413             } else
414                 continue;
415         }
416     }
417     pa_log_error("Failed to get master sink of [module-%s, filter_group:%s]", filter_name, filter_group);
418
419     return NULL;
420 }
421
422 int32_t reload_filter(pa_stream_manager *m, const char *stream_role, pa_sink *new_master_sink) {
423     filter_info *f = NULL;
424     const char *filter_name = NULL;
425     const char *filter_params = NULL;
426     const char *filter_group = NULL;
427     const char *role = NULL;
428     pa_sink *prev_master_sink = NULL;
429     pa_sink_input *i;
430     uint32_t idx;
431     int ret = 0;
432
433     pa_assert(m);
434     pa_assert(stream_role);
435     pa_assert(new_master_sink);
436
437     if (!(f = pa_hashmap_get(m->filter_infos, stream_role))) {
438         pa_log_error("could not find any filter info for [%s]", stream_role);
439         return -1;
440     }
441
442     filter_name = pa_xstrdup(f->filter_apply);
443     filter_params = pa_xstrdup(f->parameters);
444     filter_group = pa_xstrdup(f->group);
445     pa_log_debug("found filter: name[%s], params[%s], group[%s] for [%s]", filter_name, filter_params, filter_group, stream_role);
446
447     if (!(prev_master_sink = get_master_sink_of_filter(m, filter_name, filter_group))) {
448         ret = -1;
449         goto leave;
450     }
451
452     if (prev_master_sink == new_master_sink) {
453         pa_log_info("master sink is same as before, [%s], skip it", new_master_sink->name);
454         ret = 0;
455         goto leave;
456     }
457
458     if (update_filter(m, NULL, NULL, NULL, stream_role)) {
459         pa_log_error("failed to update filter to unload,");
460         ret = -1;
461         goto leave;
462     }
463
464     /* move all streams belongs to stream_role */
465     PA_IDXSET_FOREACH(i, prev_master_sink->inputs, idx) {
466         role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE);
467         if (pa_safe_streq(role, stream_role))
468             pa_sink_input_move_to(i, new_master_sink, false);
469     }
470
471     pa_log_info("name:%s, params:%s, group:%s", filter_name, filter_params, filter_group);
472     if (update_filter(m, filter_name, filter_params, filter_group, stream_role)) {
473         pa_log_error("failed to update filter to load");
474         ret = -1;
475         goto leave;
476     }
477     pa_log_info("reload filter successfully for [stream_role:%s, sink:%s]", stream_role, new_master_sink->name);
478
479 leave:
480     pa_xfree((void *)filter_name);
481     pa_xfree((void *)filter_params);
482     pa_xfree((void *)filter_group);
483
484     return ret;
485 }
486
487 static void filter_info_key_free_cb(char *key) {
488     pa_xfree(key);
489 }
490
491 static void filter_info_value_free_cb(filter_info *f) {
492     pa_assert(f);
493
494     pa_xfree((void *)f->filter_apply);
495     pa_xfree((void *)f->group);
496     pa_xfree((void *)f->parameters);
497
498     pa_xfree(f);
499 }
500
501 void init_filters(pa_stream_manager *m) {
502     pa_module *i, *module = NULL;
503     uint32_t idx;
504
505     pa_assert(m);
506
507     m->filter_infos = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func,
508                                           (pa_free_cb_t)filter_info_key_free_cb, (pa_free_cb_t)filter_info_value_free_cb);
509
510     /* Load module-filter-apply */
511     PA_IDXSET_FOREACH(i, m->core->modules, idx) {
512         if (pa_streq(i->name, MODULE_FILTER_APPLY)) {
513             module = i;
514             pa_log("module-filter-apply loaded already");
515             break;
516         }
517     }
518     if (!module) {
519         char *args = pa_sprintf_malloc("autoclean_interval=%d", 0);
520         pa_module_load(m->core, MODULE_FILTER_APPLY, args);
521         pa_log("module-filter-apply loaded");
522         pa_xfree(args);
523     }
524 }
525
526 void deinit_filters(pa_stream_manager *m) {
527     pa_module *i;
528     uint32_t idx;
529
530     pa_assert(m);
531
532     /* Unload module-filter-apply */
533     PA_IDXSET_FOREACH(i, m->core->modules, idx) {
534         if (pa_streq(i->name, MODULE_FILTER_APPLY)) {
535             pa_module_unload(m->core, i, true);
536             pa_log("module-filter-apply unloaded");
537             break;
538         }
539     }
540
541     if (m->filter_infos)
542         pa_hashmap_free(m->filter_infos);
543 }