1 From cfb39f18569679f59c9b6283c47e8d90ddd9763d Mon Sep 17 00:00:00 2001
2 From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
3 Date: Wed, 21 May 2014 14:13:41 +0300
4 Subject: [PATCH] Add module-main-volume-policy
6 Change-Id: I787141b43cafb652aa752c64ae28b6b7aa052d8e
7 Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
10 src/Makefile.am | 15 +
11 src/daemon/default.pa.in | 4 +
12 .../main-volume-policy/main-volume-context.c | 325 ++++++++++++
13 .../main-volume-policy/main-volume-context.h | 75 +++
14 .../main-volume-policy/main-volume-policy.c | 213 ++++++++
15 .../main-volume-policy.conf.example | 20 +
16 .../main-volume-policy/main-volume-policy.h | 72 +++
17 .../main-volume-policy/module-main-volume-policy.c | 556 +++++++++++++++++++++
18 9 files changed, 1283 insertions(+)
19 create mode 100644 src/modules/main-volume-policy/main-volume-context.c
20 create mode 100644 src/modules/main-volume-policy/main-volume-context.h
21 create mode 100644 src/modules/main-volume-policy/main-volume-policy.c
22 create mode 100644 src/modules/main-volume-policy/main-volume-policy.conf.example
23 create mode 100644 src/modules/main-volume-policy/main-volume-policy.h
24 create mode 100644 src/modules/main-volume-policy/module-main-volume-policy.c
26 diff --git a/Makefile.am b/Makefile.am
27 index cf4a648..646b7fc 100644
28 --- a/Makefile.am 2016-04-13 15:14:28.942023245 +0200
29 +++ b/Makefile.am 2016-04-13 15:16:32.691023039 +0200
31 moduledevvolumeapi_DATA = src/modules/volume-api/*.h
32 moduledevvolumeapidir = $(includedir)/pulsemodule/modules/volume-api
34 +moduledevmainvolumepolicy_DATA = $(top_srcdir)/src/modules/main-volume-policy/*.h
35 +moduledevmainvolumepolicydir = $(includedir)/pulsemodule/modules/main-volume-policy
39 libpulse-mainloop-glib.pc
40 libpulse-mainloop-glib.pc
41 diff --git a/src/Makefile.am b/src/Makefile.am
42 index a6bb319..8fa60ec 100644
46 libprotocol-simple.la \
48 libprotocol-native.la \
51 + libmain-volume-policy.la
54 modlibexec_LTLIBRARIES += libwebrtc-util.la
55 @@ -1051,6 +1052,12 @@ libcli_la_SOURCES = pulsecore/cli.c pulsecore/cli.h
56 libcli_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
57 libcli_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la
59 +libmain_volume_policy_la_SOURCES = \
60 + modules/main-volume-policy/main-volume-context.c modules/main-volume-policy/main-volume-context.h \
61 + modules/main-volume-policy/main-volume-policy.c modules/main-volume-policy/main-volume-policy.h
62 +libmain_volume_policy_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
63 +libmain_volume_policy_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la libvolume-api.la
65 libprotocol_cli_la_SOURCES = pulsecore/protocol-cli.c pulsecore/protocol-cli.h
66 libprotocol_cli_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
67 libprotocol_cli_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la libcli.la
68 @@ -1136,6 +1136,7 @@ endif
69 modlibexec_LTLIBRARIES += \
71 module-cli-protocol-tcp.la \
72 + module-main-volume-policy.la \
73 module-simple-protocol-tcp.la \
75 module-null-source.la \
76 @@ -1426,6 +1434,7 @@ SYMDEF_FILES = \
78 module-cli-protocol-tcp-symdef.h \
79 module-cli-protocol-unix-symdef.h \
80 + module-main-volume-policy-symdef.h \
81 module-pipe-sink-symdef.h \
82 module-pipe-source-symdef.h \
83 module-simple-protocol-tcp-symdef.h \
84 @@ -1575,6 +1584,12 @@ module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_
85 module_cli_protocol_unix_la_LDFLAGS = $(MODULE_LDFLAGS)
86 module_cli_protocol_unix_la_LIBADD = $(MODULE_LIBADD) libprotocol-cli.la
88 +# Main volume and mute policy
90 +module_main_volume_policy_la_SOURCES = modules/main-volume-policy/module-main-volume-policy.c
91 +module_main_volume_policy_la_LDFLAGS = $(MODULE_LDFLAGS)
92 +module_main_volume_policy_la_LIBADD = $(MODULE_LIBADD) libmain-volume-policy.la libvolume-api.la
96 module_http_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c
97 diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
98 index 7cf52a4..f70804c 100755
99 --- a/src/daemon/default.pa.in
100 +++ b/src/daemon/default.pa.in
105 +.ifexists module-main-volume-policy
106 +load-module module-main-volume-policy
109 ### Make some devices default
110 #set-default-sink output
111 #set-default-source input
112 diff --git a/src/modules/main-volume-policy/main-volume-context.c b/src/modules/main-volume-policy/main-volume-context.c
114 index 0000000..7ac35c6
116 +++ b/src/modules/main-volume-policy/main-volume-context.c
119 + This file is part of PulseAudio.
121 + Copyright 2014 Intel Corporation
123 + PulseAudio is free software; you can redistribute it and/or modify
124 + it under the terms of the GNU Lesser General Public License as published
125 + by the Free Software Foundation; either version 2.1 of the License,
126 + or (at your option) any later version.
128 + PulseAudio is distributed in the hope that it will be useful, but
129 + WITHOUT ANY WARRANTY; without even the implied warranty of
130 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
131 + General Public License for more details.
133 + You should have received a copy of the GNU Lesser General Public License
134 + along with PulseAudio; if not, write to the Free Software
135 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
139 +#ifdef HAVE_CONFIG_H
143 +#include "main-volume-context.h"
145 +#include <modules/volume-api/mute-control.h>
146 +#include <modules/volume-api/volume-control.h>
148 +int pa_main_volume_context_new(pa_main_volume_policy *policy, const char *name, const char *description,
149 + pa_main_volume_context **context) {
150 + pa_main_volume_context *context_local;
155 + pa_assert(description);
156 + pa_assert(context);
158 + context_local = pa_xnew0(struct pa_main_volume_context, 1);
159 + context_local->main_volume_policy = policy;
160 + context_local->index = pa_main_volume_policy_allocate_main_volume_context_index(policy);
162 + r = pa_main_volume_policy_register_name(policy, name, true, &context_local->name);
166 + context_local->description = pa_xstrdup(description);
168 + *context = context_local;
173 + pa_main_volume_context_free(context_local);
178 +void pa_main_volume_context_put(pa_main_volume_context *context) {
179 + pa_assert(context);
181 + pa_main_volume_policy_add_main_volume_context(context->main_volume_policy, context);
183 + context->linked = true;
185 + pa_log_debug("Created main volume context #%u.", context->index);
186 + pa_log_debug(" Name: %s", context->name);
187 + pa_log_debug(" Description: %s", context->description);
188 + pa_log_debug(" Main output volume control: %s",
189 + context->main_output_volume_control ? context->main_output_volume_control->name : "(unset)");
190 + pa_log_debug(" Main input volume control: %s",
191 + context->main_input_volume_control ? context->main_input_volume_control->name : "(unset)");
192 + pa_log_debug(" Main output mute control: %s",
193 + context->main_output_mute_control ? context->main_output_mute_control->name : "(unset)");
194 + pa_log_debug(" Main input mute control: %s",
195 + context->main_input_mute_control ? context->main_input_mute_control->name : "(unset)");
197 + pa_hook_fire(&context->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_PUT], context);
200 +void pa_main_volume_context_unlink(pa_main_volume_context *context) {
201 + pa_assert(context);
203 + if (context->unlinked) {
204 + pa_log_debug("Unlinking main volume context %s (already unlinked, this is a no-op).", context->name);
208 + context->unlinked = true;
210 + pa_log_debug("Unlinking main volume context %s.", context->name);
212 + if (context->linked)
213 + pa_hook_fire(&context->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK], context);
215 + if (context->main_input_mute_control_binding) {
216 + pa_binding_free(context->main_input_mute_control_binding);
217 + context->main_input_mute_control_binding = NULL;
220 + if (context->main_output_mute_control_binding) {
221 + pa_binding_free(context->main_output_mute_control_binding);
222 + context->main_output_mute_control_binding = NULL;
225 + if (context->main_input_volume_control_binding) {
226 + pa_binding_free(context->main_input_volume_control_binding);
227 + context->main_input_volume_control_binding = NULL;
230 + if (context->main_output_volume_control_binding) {
231 + pa_binding_free(context->main_output_volume_control_binding);
232 + context->main_output_volume_control_binding = NULL;
235 + context->main_input_mute_control = NULL;
236 + context->main_output_mute_control = NULL;
237 + context->main_input_volume_control = NULL;
238 + context->main_output_volume_control = NULL;
240 + pa_main_volume_policy_remove_main_volume_context(context->main_volume_policy, context);
243 +void pa_main_volume_context_free(pa_main_volume_context *context) {
244 + pa_assert(context);
246 + if (!context->unlinked)
247 + pa_main_volume_context_unlink(context);
249 + pa_xfree(context->description);
252 + pa_main_volume_policy_unregister_name(context->main_volume_policy, context->name);
257 +const char *pa_main_volume_context_get_name(pa_main_volume_context *context) {
258 + pa_assert(context);
260 + return context->name;
263 +static void set_main_output_volume_control_internal(pa_main_volume_context *context, pa_volume_control *control) {
264 + pa_volume_control *old_control;
266 + pa_assert(context);
268 + old_control = context->main_output_volume_control;
270 + if (control == old_control)
273 + context->main_output_volume_control = control;
275 + if (!context->linked || context->unlinked)
278 + pa_log_debug("The main output volume control of main volume context %s changed from %s to %s.", context->name,
279 + old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
281 + pa_hook_fire(&context->main_volume_policy->hooks
282 + [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED],
286 +void pa_main_volume_context_bind_main_output_volume_control(pa_main_volume_context *context,
287 + pa_binding_target_info *target_info) {
288 + pa_binding_owner_info owner_info = {
289 + .userdata = context,
290 + .set_value = (pa_binding_set_value_cb_t) set_main_output_volume_control_internal,
293 + pa_assert(context);
294 + pa_assert(target_info);
296 + if (context->main_output_volume_control_binding)
297 + pa_binding_free(context->main_output_volume_control_binding);
299 + context->main_output_volume_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info,
303 +static void set_main_input_volume_control_internal(pa_main_volume_context *context, pa_volume_control *control) {
304 + pa_volume_control *old_control;
306 + pa_assert(context);
308 + old_control = context->main_input_volume_control;
310 + if (control == old_control)
313 + context->main_input_volume_control = control;
315 + if (!context->linked || context->unlinked)
318 + pa_log_debug("The main input volume control of main volume context %s changed from %s to %s.", context->name,
319 + old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
321 + pa_hook_fire(&context->main_volume_policy->hooks
322 + [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_VOLUME_CONTROL_CHANGED],
326 +void pa_main_volume_context_bind_main_input_volume_control(pa_main_volume_context *context,
327 + pa_binding_target_info *target_info) {
328 + pa_binding_owner_info owner_info = {
329 + .userdata = context,
330 + .set_value = (pa_binding_set_value_cb_t) set_main_input_volume_control_internal,
333 + pa_assert(context);
334 + pa_assert(target_info);
336 + if (context->main_input_volume_control_binding)
337 + pa_binding_free(context->main_input_volume_control_binding);
339 + context->main_input_volume_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info,
343 +static void set_main_output_mute_control_internal(pa_main_volume_context *context, pa_mute_control *control) {
344 + pa_mute_control *old_control;
346 + pa_assert(context);
348 + old_control = context->main_output_mute_control;
350 + if (control == old_control)
353 + context->main_output_mute_control = control;
355 + if (!context->linked || context->unlinked)
358 + pa_log_debug("The main output mute control of main volume context %s changed from %s to %s.", context->name,
359 + old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
361 + pa_hook_fire(&context->main_volume_policy->hooks
362 + [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_MUTE_CONTROL_CHANGED],
366 +void pa_main_volume_context_bind_main_output_mute_control(pa_main_volume_context *context,
367 + pa_binding_target_info *target_info) {
368 + pa_binding_owner_info owner_info = {
369 + .userdata = context,
370 + .set_value = (pa_binding_set_value_cb_t) set_main_output_mute_control_internal,
373 + pa_assert(context);
374 + pa_assert(target_info);
376 + if (context->main_output_mute_control_binding)
377 + pa_binding_free(context->main_output_mute_control_binding);
379 + context->main_output_mute_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info,
383 +static void set_main_input_mute_control_internal(pa_main_volume_context *context, pa_mute_control *control) {
384 + pa_mute_control *old_control;
386 + pa_assert(context);
388 + old_control = context->main_input_mute_control;
390 + if (control == old_control)
393 + context->main_input_mute_control = control;
395 + if (!context->linked || context->unlinked)
398 + pa_log_debug("The main input mute control of main volume context %s changed from %s to %s.", context->name,
399 + old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
401 + pa_hook_fire(&context->main_volume_policy->hooks
402 + [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_MUTE_CONTROL_CHANGED],
406 +void pa_main_volume_context_bind_main_input_mute_control(pa_main_volume_context *context,
407 + pa_binding_target_info *target_info) {
408 + pa_binding_owner_info owner_info = {
409 + .userdata = context,
410 + .set_value = (pa_binding_set_value_cb_t) set_main_input_mute_control_internal,
413 + pa_assert(context);
414 + pa_assert(target_info);
416 + if (context->main_input_mute_control_binding)
417 + pa_binding_free(context->main_input_mute_control_binding);
419 + context->main_input_mute_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info,
423 +pa_binding_target_type *pa_main_volume_context_create_binding_target_type(pa_main_volume_policy *policy) {
424 + pa_binding_target_type *type;
428 + type = pa_binding_target_type_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, policy->main_volume_contexts,
429 + &policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_PUT],
430 + &policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK],
431 + (pa_binding_target_type_get_name_cb_t) pa_main_volume_context_get_name);
432 + pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_VOLUME_CONTROL,
433 + PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_output_volume_control));
434 + pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_VOLUME_CONTROL,
435 + PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_input_volume_control));
436 + pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_MUTE_CONTROL,
437 + PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_output_mute_control));
438 + pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_MUTE_CONTROL,
439 + PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_input_mute_control));
443 diff --git a/src/modules/main-volume-policy/main-volume-context.h b/src/modules/main-volume-policy/main-volume-context.h
445 index 0000000..4a0a6f7
447 +++ b/src/modules/main-volume-policy/main-volume-context.h
449 +#ifndef foomainvolumecontexthfoo
450 +#define foomainvolumecontexthfoo
453 + This file is part of PulseAudio.
455 + Copyright 2014 Intel Corporation
457 + PulseAudio is free software; you can redistribute it and/or modify
458 + it under the terms of the GNU Lesser General Public License as published
459 + by the Free Software Foundation; either version 2.1 of the License,
460 + or (at your option) any later version.
462 + PulseAudio is distributed in the hope that it will be useful, but
463 + WITHOUT ANY WARRANTY; without even the implied warranty of
464 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
465 + General Public License for more details.
467 + You should have received a copy of the GNU Lesser General Public License
468 + along with PulseAudio; if not, write to the Free Software
469 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
473 +#include <modules/main-volume-policy/main-volume-policy.h>
475 +#include <modules/volume-api/binding.h>
477 +typedef struct pa_main_volume_context pa_main_volume_context;
479 +#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE "MainVolumeContext"
480 +#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_VOLUME_CONTROL "main_output_volume_control"
481 +#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_VOLUME_CONTROL "main_input_volume_control"
482 +#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_MUTE_CONTROL "main_output_mute_control"
483 +#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_MUTE_CONTROL "main_input_mute_control"
485 +struct pa_main_volume_context {
486 + pa_main_volume_policy *main_volume_policy;
490 + pa_volume_control *main_output_volume_control;
491 + pa_volume_control *main_input_volume_control;
492 + pa_mute_control *main_output_mute_control;
493 + pa_mute_control *main_input_mute_control;
495 + pa_binding *main_output_volume_control_binding;
496 + pa_binding *main_input_volume_control_binding;
497 + pa_binding *main_output_mute_control_binding;
498 + pa_binding *main_input_mute_control_binding;
504 +int pa_main_volume_context_new(pa_main_volume_policy *policy, const char *name, const char *description,
505 + pa_main_volume_context **context);
506 +void pa_main_volume_context_put(pa_main_volume_context *context);
507 +void pa_main_volume_context_unlink(pa_main_volume_context *context);
508 +void pa_main_volume_context_free(pa_main_volume_context *context);
510 +const char *pa_main_volume_context_get_name(pa_main_volume_context *context);
512 +void pa_main_volume_context_bind_main_output_volume_control(pa_main_volume_context *context,
513 + pa_binding_target_info *target_info);
514 +void pa_main_volume_context_bind_main_input_volume_control(pa_main_volume_context *context,
515 + pa_binding_target_info *target_info);
516 +void pa_main_volume_context_bind_main_output_mute_control(pa_main_volume_context *context,
517 + pa_binding_target_info *target_info);
518 +void pa_main_volume_context_bind_main_input_mute_control(pa_main_volume_context *context, pa_binding_target_info *target_info);
520 +/* Called from main-volume-policy.c only. */
521 +pa_binding_target_type *pa_main_volume_context_create_binding_target_type(pa_main_volume_policy *policy);
524 diff --git a/src/modules/main-volume-policy/main-volume-policy.c b/src/modules/main-volume-policy/main-volume-policy.c
526 index 0000000..b0b4ede
528 +++ b/src/modules/main-volume-policy/main-volume-policy.c
531 + This file is part of PulseAudio.
533 + Copyright 2014 Intel Corporation
535 + PulseAudio is free software; you can redistribute it and/or modify
536 + it under the terms of the GNU Lesser General Public License as published
537 + by the Free Software Foundation; either version 2.1 of the License,
538 + or (at your option) any later version.
540 + PulseAudio is distributed in the hope that it will be useful, but
541 + WITHOUT ANY WARRANTY; without even the implied warranty of
542 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
543 + General Public License for more details.
545 + You should have received a copy of the GNU Lesser General Public License
546 + along with PulseAudio; if not, write to the Free Software
547 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
551 +#ifdef HAVE_CONFIG_H
555 +#include "main-volume-policy.h"
557 +#include <modules/main-volume-policy/main-volume-context.h>
559 +#include <pulsecore/core-util.h>
560 +#include <pulsecore/shared.h>
562 +static pa_main_volume_policy *main_volume_policy_new(pa_core *core);
563 +static void main_volume_policy_free(pa_main_volume_policy *policy);
565 +pa_main_volume_policy *pa_main_volume_policy_get(pa_core *core) {
566 + pa_main_volume_policy *policy;
570 + policy = pa_shared_get(core, "main-volume-policy");
573 + pa_main_volume_policy_ref(policy);
575 + policy = main_volume_policy_new(core);
576 + pa_assert_se(pa_shared_set(core, "main-volume-policy", policy) >= 0);
582 +pa_main_volume_policy *pa_main_volume_policy_ref(pa_main_volume_policy *policy) {
590 +void pa_main_volume_policy_unref(pa_main_volume_policy *policy) {
592 + pa_assert(policy->refcnt > 0);
596 + if (policy->refcnt == 0) {
597 + pa_assert_se(pa_shared_remove(policy->core, "main-volume-policy") >= 0);
598 + main_volume_policy_free(policy);
602 +static pa_main_volume_policy *main_volume_policy_new(pa_core *core) {
603 + pa_main_volume_policy *policy;
608 + policy = pa_xnew0(pa_main_volume_policy, 1);
609 + policy->core = core;
610 + policy->refcnt = 1;
611 + policy->volume_api = pa_volume_api_get(core);
612 + policy->names = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
613 + policy->main_volume_contexts = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
615 + for (i = 0; i < PA_MAIN_VOLUME_POLICY_HOOK_MAX; i++)
616 + pa_hook_init(&policy->hooks[i], policy);
618 + policy->main_volume_context_binding_target_type = pa_main_volume_context_create_binding_target_type(policy);
619 + pa_volume_api_add_binding_target_type(policy->volume_api, policy->main_volume_context_binding_target_type);
621 + pa_log_debug("Created a pa_main_volume_policy object.");
626 +static void main_volume_policy_free(pa_main_volume_policy *policy) {
630 + pa_assert(policy->refcnt == 0);
632 + pa_log_debug("Freeing the pa_main_volume_policy object.");
634 + if (policy->main_volume_context_binding_target_type) {
635 + pa_volume_api_remove_binding_target_type(policy->volume_api, policy->main_volume_context_binding_target_type);
636 + pa_binding_target_type_free(policy->main_volume_context_binding_target_type);
639 + for (i = 0; i < PA_MAIN_VOLUME_POLICY_HOOK_MAX; i++)
640 + pa_hook_done(&policy->hooks[i]);
642 + if (policy->main_volume_contexts) {
643 + pa_assert(pa_hashmap_isempty(policy->main_volume_contexts));
644 + pa_hashmap_free(policy->main_volume_contexts);
647 + if (policy->names) {
648 + pa_assert(pa_hashmap_isempty(policy->names));
649 + pa_hashmap_free(policy->names);
652 + if (policy->volume_api)
653 + pa_volume_api_unref(policy->volume_api);
658 +int pa_main_volume_policy_register_name(pa_main_volume_policy *policy, const char *requested_name,
659 + bool fail_if_already_registered, const char **registered_name) {
663 + pa_assert(requested_name);
664 + pa_assert(registered_name);
666 + n = pa_xstrdup(requested_name);
668 + if (pa_hashmap_put(policy->names, n, n) < 0) {
673 + if (fail_if_already_registered) {
674 + pa_log("Name %s already registered.", requested_name);
675 + return -PA_ERR_EXIST;
680 + n = pa_sprintf_malloc("%s.%u", requested_name, i);
681 + } while (pa_hashmap_put(policy->names, n, n) < 0);
684 + *registered_name = n;
689 +void pa_main_volume_policy_unregister_name(pa_main_volume_policy *policy, const char *name) {
693 + pa_assert_se(pa_hashmap_remove_and_free(policy->names, name) >= 0);
696 +uint32_t pa_main_volume_policy_allocate_main_volume_context_index(pa_main_volume_policy *policy) {
701 + idx = policy->next_main_volume_context_index++;
706 +void pa_main_volume_policy_add_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context) {
708 + pa_assert(context);
710 + pa_assert_se(pa_hashmap_put(policy->main_volume_contexts, (void *) context->name, context) >= 0);
713 +int pa_main_volume_policy_remove_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context) {
715 + pa_assert(context);
717 + if (!pa_hashmap_remove(policy->main_volume_contexts, context->name))
720 + if (context == policy->active_main_volume_context)
721 + pa_main_volume_policy_set_active_main_volume_context(policy, NULL);
726 +void pa_main_volume_policy_set_active_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context) {
727 + pa_main_volume_context *old_context;
731 + old_context = policy->active_main_volume_context;
733 + if (context == old_context)
736 + policy->active_main_volume_context = context;
738 + pa_log_debug("The active main volume context changed from %s to %s.", old_context ? old_context->name : "(unset)",
739 + context ? context->name : "(unset)");
741 + pa_hook_fire(&policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_ACTIVE_MAIN_VOLUME_CONTEXT_CHANGED], NULL);
743 diff --git a/src/modules/main-volume-policy/main-volume-policy.conf.example b/src/modules/main-volume-policy/main-volume-policy.conf.example
745 index 0000000..a4a35d3
747 +++ b/src/modules/main-volume-policy/main-volume-policy.conf.example
750 +output-volume-model = by-active-main-volume-context
751 +input-volume-model = by-active-main-volume-context
752 +output-mute-model = none
753 +input-mute-model = none
754 +main-volume-contexts = x-example-call-main-volume-context x-example-default-main-volume-context
756 +[MainVolumeContext x-example-call-main-volume-context]
757 +description = Call main volume context
758 +main-output-volume-control = bind:AudioGroup:x-example-call-downlink-audio-group
759 +main-input-volume-control = bind:AudioGroup:x-example-call-uplink-audio-group
760 +main-output-mute-control = none
761 +main-input-mute-control = none
763 +[MainVolumeContext x-example-default-main-volume-context]
764 +description = Default main volume context
765 +main-output-volume-control = bind:AudioGroup:x-example-default-output-audio-group
766 +main-input-volume-control = bind:AudioGroup:x-example-default-input-audio-group
767 +main-output-mute-control = none
768 +main-input-mute-control = none
769 diff --git a/src/modules/main-volume-policy/main-volume-policy.h b/src/modules/main-volume-policy/main-volume-policy.h
771 index 0000000..5cd669e
773 +++ b/src/modules/main-volume-policy/main-volume-policy.h
775 +#ifndef foomainvolumepolicyhfoo
776 +#define foomainvolumepolicyhfoo
779 + This file is part of PulseAudio.
781 + Copyright 2014 Intel Corporation
783 + PulseAudio is free software; you can redistribute it and/or modify
784 + it under the terms of the GNU Lesser General Public License as published
785 + by the Free Software Foundation; either version 2.1 of the License,
786 + or (at your option) any later version.
788 + PulseAudio is distributed in the hope that it will be useful, but
789 + WITHOUT ANY WARRANTY; without even the implied warranty of
790 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
791 + General Public License for more details.
793 + You should have received a copy of the GNU Lesser General Public License
794 + along with PulseAudio; if not, write to the Free Software
795 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
799 +#include <modules/volume-api/binding.h>
800 +#include <modules/volume-api/volume-api.h>
802 +#include <pulsecore/core.h>
804 +typedef struct pa_main_volume_policy pa_main_volume_policy;
806 +/* Avoid circular dependencies... */
807 +typedef struct pa_main_volume_context pa_main_volume_context;
810 + PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_PUT,
811 + PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK,
812 + PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED,
813 + PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_VOLUME_CONTROL_CHANGED,
814 + PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_MUTE_CONTROL_CHANGED,
815 + PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_MUTE_CONTROL_CHANGED,
816 + PA_MAIN_VOLUME_POLICY_HOOK_ACTIVE_MAIN_VOLUME_CONTEXT_CHANGED,
817 + PA_MAIN_VOLUME_POLICY_HOOK_MAX,
820 +struct pa_main_volume_policy {
823 + pa_volume_api *volume_api;
824 + pa_hashmap *names; /* object name -> object name (hashmap-as-a-set) */
825 + pa_hashmap *main_volume_contexts; /* name -> pa_main_volume_context */
826 + pa_main_volume_context *active_main_volume_context;
828 + uint32_t next_main_volume_context_index;
829 + pa_hook hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAX];
830 + pa_binding_target_type *main_volume_context_binding_target_type;
833 +pa_main_volume_policy *pa_main_volume_policy_get(pa_core *core);
834 +pa_main_volume_policy *pa_main_volume_policy_ref(pa_main_volume_policy *policy);
835 +void pa_main_volume_policy_unref(pa_main_volume_policy *policy);
837 +int pa_main_volume_policy_register_name(pa_main_volume_policy *policy, const char *requested_name,
838 + bool fail_if_already_registered, const char **registered_name);
839 +void pa_main_volume_policy_unregister_name(pa_main_volume_policy *policy, const char *name);
841 +uint32_t pa_main_volume_policy_allocate_main_volume_context_index(pa_main_volume_policy *policy);
842 +void pa_main_volume_policy_add_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context);
843 +int pa_main_volume_policy_remove_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context);
844 +void pa_main_volume_policy_set_active_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context);
847 diff --git a/src/modules/main-volume-policy/module-main-volume-policy.c b/src/modules/main-volume-policy/module-main-volume-policy.c
849 index 0000000..a14699d
851 +++ b/src/modules/main-volume-policy/module-main-volume-policy.c
854 + This file is part of PulseAudio.
856 + Copyright 2014 Intel Corporation
858 + PulseAudio is free software; you can redistribute it and/or modify
859 + it under the terms of the GNU Lesser General Public License as published
860 + by the Free Software Foundation; either version 2.1 of the License,
861 + or (at your option) any later version.
863 + PulseAudio is distributed in the hope that it will be useful, but
864 + WITHOUT ANY WARRANTY; without even the implied warranty of
865 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
866 + General Public License for more details.
868 + You should have received a copy of the GNU Lesser General Public License
869 + along with PulseAudio; if not, write to the Free Software
870 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
874 +#ifdef HAVE_CONFIG_H
878 +#include "module-main-volume-policy-symdef.h"
880 +#include <modules/main-volume-policy/main-volume-context.h>
882 +#include <modules/volume-api/binding.h>
883 +#include <modules/volume-api/volume-api.h>
885 +#include <pulse/direction.h>
887 +#include <pulsecore/conf-parser.h>
888 +#include <pulsecore/core-util.h>
889 +#include <pulsecore/i18n.h>
891 +PA_MODULE_AUTHOR("Tanu Kaskinen");
892 +PA_MODULE_DESCRIPTION(_("Main volume and mute policy"));
893 +PA_MODULE_VERSION(PACKAGE_VERSION);
894 +PA_MODULE_LOAD_ONCE(true);
897 + CONTROL_TYPE_VOLUME,
903 + MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT,
907 + pa_main_volume_policy *main_volume_policy;
908 + enum model output_volume_model;
909 + enum model input_volume_model;
910 + enum model output_mute_model;
911 + enum model input_mute_model;
912 + pa_hashmap *contexts; /* name -> struct context */
914 + pa_hook_slot *active_main_volume_context_changed_slot;
916 + /* The following fields are only used during initialization. */
917 + pa_hashmap *context_names; /* name -> name (hashmap-as-a-set) */
918 + pa_hashmap *unused_contexts; /* name -> struct context */
922 + struct userdata *userdata;
925 + pa_binding_target_info *main_output_volume_control_target_info;
926 + pa_binding_target_info *main_input_volume_control_target_info;
927 + pa_binding_target_info *main_output_mute_control_target_info;
928 + pa_binding_target_info *main_input_mute_control_target_info;
929 + pa_main_volume_context *main_volume_context;
934 +static void context_unlink(struct context *context);
936 +static const char *model_to_string(enum model model) {
941 + case MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT:
942 + return "by-active-main-volume-context";
945 + pa_assert_not_reached();
948 +static int model_from_string(const char *str, enum model *model) {
952 + if (pa_streq(str, "none"))
953 + *model = MODEL_NONE;
954 + else if (pa_streq(str, "by-active-main-volume-context"))
955 + *model = MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT;
957 + return -PA_ERR_INVALID;
962 +static struct context *context_new(struct userdata *u, const char *name) {
963 + struct context *context;
968 + context = pa_xnew0(struct context, 1);
969 + context->userdata = u;
970 + context->name = pa_xstrdup(name);
971 + context->description = pa_xstrdup(name);
976 +static int context_put(struct context *context) {
979 + pa_assert(context);
981 + r = pa_main_volume_context_new(context->userdata->main_volume_policy, context->name, context->description,
982 + &context->main_volume_context);
986 + if (context->main_output_volume_control_target_info)
987 + pa_main_volume_context_bind_main_output_volume_control(context->main_volume_context,
988 + context->main_output_volume_control_target_info);
990 + if (context->main_input_volume_control_target_info)
991 + pa_main_volume_context_bind_main_input_volume_control(context->main_volume_context,
992 + context->main_input_volume_control_target_info);
994 + if (context->main_output_mute_control_target_info)
995 + pa_main_volume_context_bind_main_output_mute_control(context->main_volume_context,
996 + context->main_output_mute_control_target_info);
998 + if (context->main_input_mute_control_target_info)
999 + pa_main_volume_context_bind_main_input_mute_control(context->main_volume_context,
1000 + context->main_input_mute_control_target_info);
1002 + pa_main_volume_context_put(context->main_volume_context);
1007 + context_unlink(context);
1012 +static void context_unlink(struct context *context) {
1013 + pa_assert(context);
1015 + if (context->unlinked)
1018 + context->unlinked = true;
1020 + if (context->main_volume_context) {
1021 + pa_main_volume_context_free(context->main_volume_context);
1022 + context->main_volume_context = NULL;
1026 +static void context_free(struct context *context) {
1027 + pa_assert(context);
1029 + if (!context->unlinked)
1030 + context_unlink(context);
1032 + if (context->main_input_mute_control_target_info)
1033 + pa_binding_target_info_free(context->main_input_mute_control_target_info);
1035 + if (context->main_output_mute_control_target_info)
1036 + pa_binding_target_info_free(context->main_output_mute_control_target_info);
1038 + if (context->main_input_volume_control_target_info)
1039 + pa_binding_target_info_free(context->main_input_volume_control_target_info);
1041 + if (context->main_output_volume_control_target_info)
1042 + pa_binding_target_info_free(context->main_output_volume_control_target_info);
1044 + pa_xfree(context->description);
1045 + pa_xfree(context->name);
1046 + pa_xfree(context);
1049 +static void context_set_description(struct context *context, const char *description) {
1050 + pa_assert(context);
1051 + pa_assert(description);
1053 + pa_xfree(context->description);
1054 + context->description = pa_xstrdup(description);
1057 +static void context_set_main_control_target_info(struct context *context, enum control_type type, pa_direction_t direction,
1058 + pa_binding_target_info *info) {
1059 + pa_assert(context);
1062 + case CONTROL_TYPE_VOLUME:
1063 + if (direction == PA_DIRECTION_OUTPUT) {
1064 + if (context->main_output_volume_control_target_info)
1065 + pa_binding_target_info_free(context->main_output_volume_control_target_info);
1068 + context->main_output_volume_control_target_info = pa_binding_target_info_copy(info);
1070 + context->main_output_volume_control_target_info = NULL;
1072 + if (context->main_input_volume_control_target_info)
1073 + pa_binding_target_info_free(context->main_input_volume_control_target_info);
1076 + context->main_input_volume_control_target_info = pa_binding_target_info_copy(info);
1078 + context->main_input_volume_control_target_info = NULL;
1082 + case CONTROL_TYPE_MUTE:
1083 + if (direction == PA_DIRECTION_OUTPUT) {
1084 + if (context->main_output_mute_control_target_info)
1085 + pa_binding_target_info_free(context->main_output_mute_control_target_info);
1088 + context->main_output_mute_control_target_info = pa_binding_target_info_copy(info);
1090 + context->main_output_mute_control_target_info = NULL;
1092 + if (context->main_input_mute_control_target_info)
1093 + pa_binding_target_info_free(context->main_input_mute_control_target_info);
1096 + context->main_input_mute_control_target_info = pa_binding_target_info_copy(info);
1098 + context->main_input_mute_control_target_info = NULL;
1104 +static pa_hook_result_t active_main_volume_context_changed_cb(void *hook_data, void *call_data, void *userdata) {
1105 + struct userdata *u = userdata;
1106 + pa_main_volume_context *context;
1107 + pa_volume_api *api;
1108 + pa_binding_target_info *info = NULL;
1112 + context = u->main_volume_policy->active_main_volume_context;
1113 + api = u->main_volume_policy->volume_api;
1115 + if (u->output_volume_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
1117 + info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name,
1118 + PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_VOLUME_CONTROL);
1119 + pa_volume_api_bind_main_output_volume_control(api, info);
1121 + pa_volume_api_set_main_output_volume_control(api, NULL);
1124 + if (u->input_volume_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
1126 + info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name,
1127 + PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_VOLUME_CONTROL);
1128 + pa_volume_api_bind_main_input_volume_control(api, info);
1130 + pa_volume_api_set_main_input_volume_control(api, NULL);
1133 + if (u->output_mute_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
1135 + info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name,
1136 + PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_MUTE_CONTROL);
1137 + pa_volume_api_bind_main_output_mute_control(api, info);
1139 + pa_volume_api_set_main_output_mute_control(api, NULL);
1142 + if (u->input_mute_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
1144 + info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name,
1145 + PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_MUTE_CONTROL);
1146 + pa_volume_api_bind_main_input_mute_control(api, info);
1148 + pa_volume_api_set_main_input_mute_control(api, NULL);
1152 + pa_binding_target_info_free(info);
1154 + return PA_HOOK_OK;
1157 +static int parse_model(pa_config_parser_state *state) {
1162 + r = model_from_string(state->rvalue, state->data);
1164 + pa_log("[%s:%u] Failed to parse model: %s", state->filename, state->lineno, state->rvalue);
1169 +static int parse_main_volume_contexts(pa_config_parser_state *state) {
1170 + struct userdata *u;
1172 + const char *split_state = NULL;
1176 + u = state->userdata;
1178 + while ((name = pa_split_spaces(state->rvalue, &split_state)))
1179 + pa_hashmap_put(u->context_names, name, name);
1184 +static struct context *get_context(struct userdata *u, const char *section) {
1186 + struct context *context;
1193 + if (!pa_startswith(section, "MainVolumeContext "))
1196 + name = section + 18;
1198 + context = pa_hashmap_get(u->unused_contexts, name);
1200 + context = context_new(u, name);
1201 + pa_hashmap_put(u->unused_contexts, context->name, context);
1207 +static int parse_description(pa_config_parser_state *state) {
1208 + struct userdata *u;
1209 + struct context *context;
1213 + u = state->userdata;
1215 + context = get_context(u, state->section);
1217 + pa_log("[%s:%u] Key \"%s\" not expected in section %s.", state->filename, state->lineno, state->lvalue,
1218 + pa_strnull(state->section));
1219 + return -PA_ERR_INVALID;
1222 + context_set_description(context, state->rvalue);
1227 +static const char *get_target_field_name(enum control_type type) {
1229 + case CONTROL_TYPE_VOLUME:
1230 + return "volume_control";
1232 + case CONTROL_TYPE_MUTE:
1233 + return "mute_control";
1236 + pa_assert_not_reached();
1239 +static int parse_main_control(pa_config_parser_state *state, enum control_type type, pa_direction_t direction) {
1240 + struct userdata *u;
1241 + struct context *context;
1245 + u = state->userdata;
1247 + context = get_context(u, state->section);
1249 + pa_log("[%s:%u] Key \"%s\" not expected in section %s.", state->filename, state->lineno, state->lvalue,
1250 + pa_strnull(state->section));
1251 + return -PA_ERR_INVALID;
1254 + if (pa_streq(state->rvalue, "none"))
1255 + context_set_main_control_target_info(context, type, direction, NULL);
1256 + else if (pa_startswith(state->rvalue, "bind:")) {
1258 + pa_binding_target_info *info;
1260 + r = pa_binding_target_info_new_from_string(state->rvalue, get_target_field_name(type), &info);
1262 + pa_log("[%s:%u] Failed to parse binding target \"%s\".", state->filename, state->lineno, state->rvalue);
1266 + context_set_main_control_target_info(context, type, direction, info);
1267 + pa_binding_target_info_free(info);
1269 + pa_log("[%s:%u] Failed to parse value \"%s\".", state->filename, state->lineno, state->rvalue);
1270 + return -PA_ERR_INVALID;
1276 +static int parse_main_output_volume_control(pa_config_parser_state *state) {
1279 + return parse_main_control(state, CONTROL_TYPE_VOLUME, PA_DIRECTION_OUTPUT);
1282 +static int parse_main_input_volume_control(pa_config_parser_state *state) {
1285 + return parse_main_control(state, CONTROL_TYPE_VOLUME, PA_DIRECTION_INPUT);
1288 +static int parse_main_output_mute_control(pa_config_parser_state *state) {
1291 + return parse_main_control(state, CONTROL_TYPE_MUTE, PA_DIRECTION_OUTPUT);
1294 +static int parse_main_input_mute_control(pa_config_parser_state *state) {
1297 + return parse_main_control(state, CONTROL_TYPE_MUTE, PA_DIRECTION_INPUT);
1300 +static void finalize_config(struct userdata *u) {
1301 + const char *context_name;
1303 + struct context *context;
1307 + PA_HASHMAP_FOREACH(context_name, u->context_names, state) {
1310 + context = pa_hashmap_remove(u->unused_contexts, context_name);
1312 + context = context_new(u, context_name);
1314 + r = context_put(context);
1316 + pa_log_warn("Failed to create main volume context %s.", context_name);
1317 + context_free(context);
1321 + pa_assert_se(pa_hashmap_put(u->contexts, context->name, context) >= 0);
1324 + PA_HASHMAP_FOREACH(context, u->unused_contexts, state)
1325 + pa_log_debug("Main volume context %s is not used.", context->name);
1327 + pa_hashmap_free(u->unused_contexts);
1328 + u->unused_contexts = NULL;
1330 + pa_hashmap_free(u->context_names);
1331 + u->context_names = NULL;
1334 +int pa__init(pa_module *module) {
1335 + struct userdata *u;
1339 + pa_assert(module);
1341 + u = module->userdata = pa_xnew0(struct userdata, 1);
1342 + u->main_volume_policy = pa_main_volume_policy_get(module->core);
1343 + u->output_volume_model = MODEL_NONE;
1344 + u->input_volume_model = MODEL_NONE;
1345 + u->output_mute_model = MODEL_NONE;
1346 + u->input_mute_model = MODEL_NONE;
1347 + u->contexts = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
1348 + (pa_free_cb_t) context_free);
1349 + u->active_main_volume_context_changed_slot =
1350 + pa_hook_connect(&u->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_ACTIVE_MAIN_VOLUME_CONTEXT_CHANGED],
1351 + PA_HOOK_NORMAL, active_main_volume_context_changed_cb, u);
1352 + u->context_names = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
1353 + u->unused_contexts = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
1354 + (pa_free_cb_t) context_free);
1356 + f = pa_open_config_file(PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "main-volume-policy.conf", "main-volume-policy.conf", NULL, &fn);
1358 + pa_config_item config_items[] = {
1359 + { "output-volume-model", parse_model, &u->output_volume_model, "General" },
1360 + { "input-volume-model", parse_model, &u->input_volume_model, "General" },
1361 + { "output-mute-model", parse_model, &u->output_mute_model, "General" },
1362 + { "input-mute-model", parse_model, &u->input_mute_model, "General" },
1363 + { "main-volume-contexts", parse_main_volume_contexts, NULL, "General" },
1364 + { "description", parse_description, NULL, NULL },
1365 + { "main-output-volume-control", parse_main_output_volume_control, NULL, NULL },
1366 + { "main-input-volume-control", parse_main_input_volume_control, NULL, NULL },
1367 + { "main-output-mute-control", parse_main_output_mute_control, NULL, NULL },
1368 + { "main-input-mute-control", parse_main_input_mute_control, NULL, NULL },
1372 + pa_config_parse(fn, f, config_items, NULL, u);
1379 + finalize_config(u);
1381 + pa_log_debug("Output volume model: %s", model_to_string(u->output_volume_model));
1382 + pa_log_debug("Input volume model: %s", model_to_string(u->input_volume_model));
1383 + pa_log_debug("Output mute model: %s", model_to_string(u->output_mute_model));
1384 + pa_log_debug("Input mute model: %s", model_to_string(u->input_mute_model));
1389 +void pa__done(pa_module *module) {
1390 + struct userdata *u;
1392 + pa_assert(module);
1394 + u = module->userdata;
1398 + if (u->active_main_volume_context_changed_slot)
1399 + pa_hook_slot_free(u->active_main_volume_context_changed_slot);
1402 + pa_hashmap_free(u->contexts);
1404 + if (u->main_volume_policy)
1405 + pa_main_volume_policy_unref(u->main_volume_policy);
1412 --- a/po/POTFILES.in 2016-04-14 13:03:50.715006116 +0200
1413 +++ b/po/POTFILES.in 2016-04-14 13:04:23.097006062 +0200
1415 src/utils/pax11publish.c
1416 src/modules/volume-api/device-creator.c
1417 src/pulse/ext-volume-api.c
1418 +src/modules/main-volume-policy/module-main-volume-policy.c