moduledevinternal_DATA = src/pulse/internal.h src/pulse/client-conf.h src/pulse/fork-detect.h
moduledevinternaldir = $(includedir)/pulsemodule/pulse
-moduledevvolumeapi_DATA = src/modules/volume-api/*.h
-moduledevvolumeapidir = $(includedir)/pulsemodule/modules/volume-api
-
-moduledevmainvolumepolicy_DATA = src/modules/main-volume-policy/*.h
-moduledevmainvolumepolicydir = $(includedir)/pulsemodule/modules/main-volume-policy
-
filterdir = /etc/pulse/filter
filter_DATA = filter/filter_44100_48000.dat \
filter/filter_44100_8000.dat \
Name: pulseaudio
Summary: Improved Linux sound server
Version: 5.0
-Release: 106
+Release: 107
Group: Multimedia/Audio
License: LGPL-2.1+
URL: http://pulseaudio.org
%else
%{_unitdir}/multi-user.target.wants/pulseaudio.service
%endif
-%{_libdir}/pulse-%{version}/modules/libvolume-api.so
-%{_libdir}/pulse-%{version}/modules/libmain-volume-policy.so
-%{_libdir}/pulse-%{version}/modules/module-volume-api.so
-%{_libdir}/pulse-%{version}/modules/module-main-volume-policy.so
-%{_libdir}/pulse-%{version}/modules/module-audio-groups.so
%exclude %config(noreplace) /etc/bash_completion.d/pulseaudio-bash-completion.sh
%config(noreplace) %{_sysconfdir}/pulse/default.pa
%config(noreplace) %{_sysconfdir}/pulse/client.conf
%config(noreplace) %{_sysconfdir}/pulse/system.pa
-%config(noreplace) %{_sysconfdir}/pulse/audio-groups.conf
-%config(noreplace) %{_sysconfdir}/pulse/main-volume-policy.conf
%{_datadir}/pulseaudio/alsa-mixer/paths/*
%{_datadir}/pulseaudio/alsa-mixer/profile-sets/*
%defattr(-,root,root)
%{_includedir}/pulsemodule/pulsecore/*.h
%{_includedir}/pulsemodule/pulse/*.h
-%{_includedir}/pulsemodule/modules/main-volume-policy/*.h
-%{_includedir}/pulsemodule/modules/volume-api/*.h
%{_libdir}/pkgconfig/pulseaudio-module-devel.pc
%files vala-bindings
daemon/cascaded.pa \
pulse/client.conf.in \
pulse/version.h.in \
- tizen-ivi/audio-groups.conf \
- tizen-ivi/main-volume-policy.conf \
daemon/daemon.conf.in \
daemon/default.pa.in \
daemon/system.pa.in \
daemon.conf \
client.conf
-# Add some Tizen specific configuration files.
-#
-# FIXME: These configuration files should be installed only if explicitly
-# requested, because they define policy which may not be the desired policy in
-# every Tizen profile. Currently default.pa loads module-audio-groups and
-# module-main-volume-policy only if module-murphy-ivi is installed in the
-# system, which helps with this issue, because non-IVI profiles don't
-# currently use module-murphy-ivi, so these configuration files won't have any
-# effect outside the IVI profile, but this is pretty hacky solution. It would
-# be better to load module-audio-groups and module-main-volume-policy
-# unconditionally, since they're not really tied to the Murphy module in any
-# way. We use this hack, because otherwise we'd need a configure switch for
-# enabling the example IVI configuration, and a new configure switch would also
-# require a new switch in the Tizen IVI image configuration. That's an extra
-# hurdle that we decided to avoid for now.
-pulseconf_DATA += \
- tizen-ivi/audio-groups.conf \
- tizen-ivi/main-volume-policy.conf
-
if HAVE_DBUS
dbuspolicy_DATA = \
daemon/pulseaudio-system.conf
pulse/ext-stream-restore.h \
pulse/ext-echo-cancel.h \
pulse/ext-node-manager.h \
- pulse/ext-volume-api.h \
pulse/format.h \
pulse/gccmacro.h \
pulse/introspect.h \
pulse/ext-stream-restore.c pulse/ext-stream-restore.h \
pulse/ext-echo-cancel.c pulse/ext-echo-cancel.h \
pulse/ext-node-manager.c pulse/ext-node-manager.h \
- pulse/ext-volume-api.c pulse/ext-volume-api.h modules/volume-api/volume-api-common.h \
pulse/format.c pulse/format.h \
pulse/gccmacro.h \
pulse/internal.h \
modlibexec_LTLIBRARIES = \
libcli.la \
- libmain-volume-policy.la \
libprotocol-cli.la \
libprotocol-simple.la \
libprotocol-http.la \
- libprotocol-native.la \
- libvolume-api.la
+ libprotocol-native.la
if HAVE_SYSTEMD_LOGIN
modlibexec_LTLIBRARIES += \
liblogind_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
liblogind_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la
-libmain_volume_policy_la_SOURCES = \
- modules/main-volume-policy/main-volume-context.c modules/main-volume-policy/main-volume-context.h \
- modules/main-volume-policy/main-volume-policy.c modules/main-volume-policy/main-volume-policy.h
-libmain_volume_policy_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
-libmain_volume_policy_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la libvolume-api.la
-
libprotocol_cli_la_SOURCES = pulsecore/protocol-cli.c pulsecore/protocol-cli.h
libprotocol_cli_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
libprotocol_cli_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la libcli.la
libtunnel_manager_la_LIBADD += liblogind.la
endif
-libvolume_api_la_SOURCES = \
- modules/volume-api/audio-group.c modules/volume-api/audio-group.h \
- modules/volume-api/bvolume.h \
- modules/volume-api/device.c modules/volume-api/device.h \
- modules/volume-api/device-creator.c modules/volume-api/device-creator.h \
- modules/volume-api/inidb.c modules/volume-api/inidb.h \
- modules/volume-api/mute-control.c modules/volume-api/mute-control.h \
- modules/volume-api/sstream.c modules/volume-api/sstream.h \
- modules/volume-api/stream-creator.c modules/volume-api/stream-creator.h \
- modules/volume-api/volume-api.c modules/volume-api/volume-api.h \
- modules/volume-api/volume-control.c modules/volume-api/volume-control.h
-libvolume_api_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
-libvolume_api_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la
-
-# Audio Groups
-module_audio_groups_la_SOURCES = modules/audio-groups/module-audio-groups.c
-module_audio_groups_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_audio_groups_la_LIBADD = $(MODULE_LIBADD) libvolume-api.la
-module_audio_groups_la_CFLAGS = $(AM_CFLAGS)
-
if HAVE_ESOUND
libprotocol_esound_la_SOURCES = pulsecore/protocol-esound.c pulsecore/protocol-esound.h pulsecore/esound.h
libprotocol_esound_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
modlibexec_LTLIBRARIES += \
module-cli.la \
module-cli-protocol-tcp.la \
- module-main-volume-policy.la \
module-simple-protocol-tcp.la \
module-tunnel-manager.la \
- module-volume-api.la \
module-null-sink.la \
module-null-source.la \
module-sine-source.la \
module-switch-on-port-available.la \
module-filter-apply.la \
module-filter-heuristics.la \
- module-role-ducking.la \
- module-audio-groups.la
+ module-role-ducking.la
if HAVE_ESOUND
modlibexec_LTLIBRARIES += \
module-cli-symdef.h \
module-cli-protocol-tcp-symdef.h \
module-cli-protocol-unix-symdef.h \
- module-main-volume-policy-symdef.h \
module-pipe-sink-symdef.h \
module-pipe-source-symdef.h \
module-simple-protocol-tcp-symdef.h \
module-simple-protocol-unix-symdef.h \
module-tunnel-manager-symdef.h \
- module-volume-api-symdef.h \
module-native-protocol-tcp-symdef.h \
module-native-protocol-unix-symdef.h \
module-native-protocol-fd-symdef.h \
module-switch-on-connect-symdef.h \
module-switch-on-port-available-symdef.h \
module-filter-apply-symdef.h \
- module-filter-heuristics-symdef.h \
- module-audio-groups-symdef.h
+ module-filter-heuristics-symdef.h
if HAVE_ESOUND
SYMDEF_FILES += \
module_tunnel_manager_la_LDFLAGS = $(MODULE_LDFLAGS)
module_tunnel_manager_la_LIBADD = $(MODULE_LIBADD) libtunnel-manager.la
-# Volume API
-
-module_volume_api_la_SOURCES = \
- modules/volume-api/module-volume-api.c \
- modules/volume-api/volume-api-common.h
-module_volume_api_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_volume_api_la_LIBADD = $(MODULE_LIBADD) libprotocol-native.la libvolume-api.la
-
# CLI protocol
module_cli_la_SOURCES = modules/module-cli.c
module_cli_protocol_unix_la_LDFLAGS = $(MODULE_LDFLAGS)
module_cli_protocol_unix_la_LIBADD = $(MODULE_LIBADD) libprotocol-cli.la
-# Main volume and mute policy
-
-module_main_volume_policy_la_SOURCES = modules/main-volume-policy/module-main-volume-policy.c
-module_main_volume_policy_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_main_volume_policy_la_LIBADD = $(MODULE_LIBADD) libmain-volume-policy.la libvolume-api.la
-
# HTTP protocol
module_http_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c
load-module module-native-protocol-tcp listen=127.0.0.1
.fail
-load-module module-volume-api
-load-module module-audio-groups
-load-module module-main-volume-policy
.else
### Automatically restore the volume of streams and devices
load-module module-device-restore
+++ /dev/null
-[General]
-stream-rules = phone-output music-output default-output
-
-[AudioGroup x-example-call-downlink-audio-group]
-volume-control = create:call-downlink-volume-control
-mute-control = create:call-downlink-mute-control
-
-[AudioGroup x-example-default-output-audio-group]
-volume-control = create:default-output-volume-control
-mute-control = create:call-downlink-mute-control
-
-[AudioGroup x-example-music-output-audio-group]
-volume-control = bind:AudioGroup:x-example-default-output-audio-group
-mute-control = bind:AudioGroup:x-example-default-output-audio-group
-
-[StreamRule phone-output]
-match = (direction output AND property media.role=phone)
-audio-group-for-volume = x-example-call-downlink-audio-group
-audio-group-for-mute = x-example-call-downlink-audio-group
-
-[StreamRule music-output]
-match = (direction output AND property media.role=music)
-audio-group-for-volume = x-example-music-output-audio-group
-audio-group-for-mute = x-example-music-output-audio-group
-
-[StreamRule default-output]
-match = (direction output)
-audio-group-for-volume = x-example-default-output-audio-group
-audio-group-for-mute = x-example-default-output-audio-group
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-
-#include <pulse/xmalloc.h>
-
-#include <pulsecore/core-util.h>
-#include <pulsecore/dynarray.h>
-#include <pulsecore/module.h>
-#include <pulsecore/modargs.h>
-#include <pulsecore/conf-parser.h>
-#include <pulsecore/hashmap.h>
-
-#include <modules/volume-api/sstream.h>
-#include <modules/volume-api/volume-control.h>
-#include <modules/volume-api/audio-group.h>
-
-#include "module-audio-groups-symdef.h"
-
-#define AUDIOGROUP_START "AudioGroup "
-#define STREAM_RULE_START "StreamRule "
-#define NONE_KEYWORD "none"
-#define CREATE_PREFIX "create:"
-#define BIND_PREFIX "bind:"
-#define BIND_AUDIO_GROUP_PREFIX BIND_PREFIX "AudioGroup:"
-
-PA_MODULE_AUTHOR("Ismo Puustinen");
-PA_MODULE_DESCRIPTION("Create audio groups and classify streams to them");
-PA_MODULE_VERSION(PACKAGE_VERSION);
-PA_MODULE_LOAD_ONCE(true);
-
-enum match_direction {
- match_direction_unknown = 0,
- match_direction_input,
- match_direction_output,
-};
-
-/* logical expressions */
-
-struct literal {
-
- /* TODO: this might be parsed to some faster-to-check format? */
-
- char *property_name;
- char *property_value;
- enum match_direction stream_direction;
-
- bool negation;
- PA_LLIST_FIELDS(struct literal);
-};
-
-struct conjunction {
- /* a conjunction of literals */
- PA_LLIST_HEAD(struct literal, literals);
- PA_LLIST_FIELDS(struct conjunction);
-};
-
-struct expression {
- /* this is in disjunctive normal form, so a disjunction of conjunctions */
- PA_LLIST_HEAD(struct conjunction, conjunctions);
-};
-
-struct group {
- struct userdata *userdata;
- pa_audio_group *audio_group;
- struct control *volume_control;
- struct control *mute_control;
- char *own_volume_control_name;
- char *own_mute_control_name;
- struct group *volume_master;
- struct group *mute_master;
- char *volume_master_name;
- char *mute_master_name;
-
- pa_hashmap *volume_slaves; /* struct group -> struct group (hashmap-as-a-set) */
- pa_hashmap *mute_slaves; /* struct group -> struct group (hashmap-as-a-set) */
- pa_hashmap *volume_stream_rules; /* struct stream_rule -> struct stream_rule (hashmap-as-a-set) */
- pa_hashmap *mute_stream_rules; /* struct stream_rule -> struct stream_rule (hashmap-as-a-set) */
-
- bool unlinked;
-};
-
-enum control_type {
- CONTROL_TYPE_VOLUME,
- CONTROL_TYPE_MUTE,
-};
-
-struct control {
- struct userdata *userdata;
- enum control_type type;
-
- union {
- pa_volume_control *volume_control;
- pa_mute_control *mute_control;
- };
-
- /* Controls that are created for streams don't own their pa_volume_control
- * and pa_mute_control objects, because they're owned by the streams. */
- bool own_control;
-
- /* If non-NULL, then this control mirrors the state of the master
- * control. If someone changes the master state, the state of this control
- * is also updated, and also if someone changes this control's state, the
- * change is applied also to the master. */
- struct control *master;
-
- /* struct control -> struct control (hashmap-as-a-set)
- * Contains the controls that have this control as their master. */
- pa_hashmap *slaves;
-
- /* Set to true when the master control's state has been copied to this
- * control. */
- bool synced_with_master;
-
- bool acquired;
- bool unlinked;
-};
-
-struct stream_rule {
- struct userdata *userdata;
- char *name;
- enum match_direction direction;
- char *audio_group_name_for_volume;
- char *audio_group_name_for_mute;
- struct group *group_for_volume;
- struct group *group_for_mute;
- struct expression *match_expression;
-};
-
-struct userdata {
- pa_volume_api *volume_api;
- pa_hashmap *groups; /* name -> struct group */
- pa_hashmap *stream_rules; /* name -> struct stream_rule */
- pa_dynarray *stream_rules_list; /* struct stream_rule */
-
- /* pas_stream -> struct stream_rule
- * When a stream matches with a rule, it's added here. */
- pa_hashmap *rules_by_stream;
-
- /* pas_stream -> struct control
- * Contains proxy controls for all relative volume controls of streams. */
- pa_hashmap *stream_volume_controls;
-
- /* pas_stream -> struct control
- * Contains proxy controls for all mute controls of streams. */
- pa_hashmap *stream_mute_controls;
-
- pa_hook_slot *stream_put_slot;
- pa_hook_slot *stream_unlink_slot;
- pa_hook_slot *volume_control_implementation_initialized_slot;
- pa_hook_slot *mute_control_implementation_initialized_slot;
- pa_hook_slot *volume_control_set_initial_volume_slot;
- pa_hook_slot *mute_control_set_initial_mute_slot;
- pa_hook_slot *volume_control_volume_changed_slot;
- pa_hook_slot *mute_control_mute_changed_slot;
- pa_hook_slot *volume_control_unlink_slot;
- pa_hook_slot *mute_control_unlink_slot;
-
- pa_dynarray *stream_rule_names; /* Only used during initialization. */
-};
-
-static const char* const valid_modargs[] = {
- "filename",
- NULL
-};
-
-static void control_free(struct control *control);
-static void control_set_master(struct control *control, struct control *master);
-static void control_add_slave(struct control *control, struct control *slave);
-static void control_remove_slave(struct control *control, struct control *slave);
-
-static void group_free(struct group *group);
-static void group_set_master(struct group *group, enum control_type type, struct group *master);
-static int group_set_master_name(struct group *group, enum control_type type, const char *name);
-static void group_disable_control(struct group *group, enum control_type type);
-static void group_add_slave(struct group *group, enum control_type type, struct group *slave);
-static void group_remove_slave(struct group *group, enum control_type type, struct group *slave);
-
-static void stream_rule_set_group(struct stream_rule *rule, enum control_type type, struct group *group);
-static void stream_rule_set_group_name(struct stream_rule *rule, enum control_type type, const char *name);
-
-static bool literal_match(struct literal *literal, pas_stream *stream);
-
-static struct expression *expression_new(void);
-static void expression_free(struct expression *expression);
-
-static int volume_control_set_volume_cb(pa_volume_control *volume_control, const pa_bvolume *original_volume,
- const pa_bvolume *remapped_volume, bool set_volume, bool set_balance) {
- struct control *control;
- struct control *slave;
- void *state;
-
- pa_assert(volume_control);
- pa_assert(original_volume);
- pa_assert(remapped_volume);
-
- control = volume_control->userdata;
-
- /* There are four cases that need to be considered:
- *
- * 1) The master control is propagating the volume to this control. We need
- * to propagate the volume downstream.
- *
- * 2) This control was just assigned a master control and the volume hasn't
- * yet been synchronized. In this case the volume that is now being set for
- * this control is the master control's volume. We need to propagate the
- * volume downstream.
- *
- * 3) Someone set the volume directly for this control, and this control
- * has a master control. We need to propagate the volume upstream, and wait
- * for another call that will fall under the case 1.
- *
- * 4) Someone set the volume directly for this control, and this control
- * doesn't have a master control. We need to propagate the volume
- * downstream.
- *
- * As we can see, the action is the same in cases 1, 2 and 4. */
-
- /* Case 3. */
- if (control->synced_with_master && !control->master->volume_control->set_volume_in_progress) {
- pa_volume_control_set_volume(control->master->volume_control, original_volume, set_volume, set_balance);
- return 0;
- }
-
- /* Cases 1, 2 and 4. */
- PA_HASHMAP_FOREACH(slave, control->slaves, state)
- pa_volume_control_set_volume(slave->volume_control, original_volume, set_volume, set_balance);
-
- return 0;
-}
-
-static int mute_control_set_mute_cb(pa_mute_control *mute_control, bool mute) {
- struct control *control;
- struct control *slave;
- void *state;
-
- pa_assert(mute_control);
-
- control = mute_control->userdata;
-
- /* There are four cases that need to be considered:
- *
- * 1) The master control is propagating the mute to this control. We need
- * to propagate the mute downstream.
- *
- * 2) This control was just assigned a master control and the mute hasn't
- * yet been synchronized. In this case the mute that is now being set for
- * this control is the master control's mute. We need to propagate the mute
- * downstream.
- *
- * 3) Someone set the mute directly for this control, and this control has
- * a master control. We need to propagate the mute upstream, and wait for
- * another call that will fall under the case 1.
- *
- * 4) Someone set the mute directly for this control, and this control
- * doesn't have a master control. We need to propagate the mute downstream.
- *
- * As we can see, the action is the same in cases 1, 2 and 4. */
-
- /* Case 3. */
- if (control->synced_with_master && !control->master->mute_control->set_mute_in_progress) {
- pa_mute_control_set_mute(control->master->mute_control, mute);
- return 0;
- }
-
- /* Cases 1, 2 and 4. */
- PA_HASHMAP_FOREACH(slave, control->slaves, state)
- pa_mute_control_set_mute(slave->mute_control, mute);
-
- return 0;
-}
-
-static int control_new_for_group(struct group *group, enum control_type type, const char *name, bool persistent, struct control **_r) {
- struct control *control = NULL;
- int r = 0;
-
- pa_assert(group);
- pa_assert(name);
- pa_assert(_r);
-
- control = pa_xnew0(struct control, 1);
- control->userdata = group->userdata;
- control->type = type;
- control->slaves = pa_hashmap_new(NULL, NULL);
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- if (persistent)
- control->volume_control = pa_hashmap_get(control->userdata->volume_api->volume_controls, name);
-
- if (!control->volume_control) {
- r = pa_volume_control_new(control->userdata->volume_api, name, persistent, &control->volume_control);
- if (r < 0)
- goto fail;
- }
-
- pa_volume_control_set_convertible_to_dB(control->volume_control, true);
-
- if (persistent) {
- r = pa_volume_control_acquire_for_audio_group(control->volume_control, group->audio_group,
- volume_control_set_volume_cb, control);
- if (r < 0)
- goto fail;
-
- control->acquired = true;
- } else {
- control->volume_control->set_volume = volume_control_set_volume_cb;
- control->volume_control->userdata = control;
- }
- break;
-
- case CONTROL_TYPE_MUTE:
- if (persistent)
- control->mute_control = pa_hashmap_get(control->userdata->volume_api->mute_controls, name);
-
- if (!control->mute_control) {
- r = pa_mute_control_new(control->userdata->volume_api, name, persistent, &control->mute_control);
- if (r < 0)
- goto fail;
- }
-
- if (persistent) {
- r = pa_mute_control_acquire_for_audio_group(control->mute_control, group->audio_group,
- mute_control_set_mute_cb, control);
- if (r < 0)
- goto fail;
-
- control->acquired = true;
- } else {
- control->mute_control->set_mute = mute_control_set_mute_cb;
- control->mute_control->userdata = control;
- }
- break;
- }
-
- control->own_control = true;
-
- *_r = control;
- return 0;
-
-fail:
- if (control)
- control_free(control);
-
- return r;
-}
-
-static struct control *control_new_for_stream(struct userdata *u, enum control_type type, pas_stream *stream) {
- struct control *control;
-
- pa_assert(u);
- pa_assert(stream);
-
- control = pa_xnew0(struct control, 1);
- control->userdata = u;
- control->type = type;
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- control->volume_control = stream->relative_volume_control;
- pa_assert(control->volume_control);
- break;
-
- case CONTROL_TYPE_MUTE:
- control->mute_control = stream->mute_control;
- pa_assert(control->mute_control);
- break;
- }
-
- return control;
-}
-
-static void control_put(struct control *control) {
- pa_assert(control);
-
- switch (control->type) {
- case CONTROL_TYPE_VOLUME:
- if (control->own_control && !control->volume_control->linked)
- pa_volume_control_put(control->volume_control);
- break;
-
- case CONTROL_TYPE_MUTE:
- if (control->own_control && !control->mute_control->linked)
- pa_mute_control_put(control->mute_control);
- break;
- }
-}
-
-static void control_unlink(struct control *control) {
- pa_assert(control);
-
- if (control->unlinked)
- return;
-
- control->unlinked = true;
-
- if (control->slaves) {
- struct control *slave;
-
- while ((slave = pa_hashmap_first(control->slaves)))
- control_set_master(slave, NULL);
- }
-
- control_set_master(control, NULL);
-
- switch (control->type) {
- case CONTROL_TYPE_VOLUME:
- if (control->own_control && control->volume_control && !control->volume_control->persistent)
- pa_volume_control_unlink(control->volume_control);
- break;
-
- case CONTROL_TYPE_MUTE:
- if (control->own_control && control->mute_control && !control->mute_control->persistent)
- pa_mute_control_unlink(control->mute_control);
- break;
- }
-}
-
-static void control_free(struct control *control) {
- pa_assert(control);
-
- if (!control->unlinked)
- control_unlink(control);
-
- if (control->slaves) {
- pa_assert(pa_hashmap_isempty(control->slaves));
- pa_hashmap_free(control->slaves);
- }
-
- switch (control->type) {
- case CONTROL_TYPE_VOLUME:
- if (control->acquired)
- pa_volume_control_release(control->volume_control);
-
- if (control->own_control && control->volume_control && !control->volume_control->persistent)
- pa_volume_control_free(control->volume_control);
- break;
-
- case CONTROL_TYPE_MUTE:
- if (control->acquired)
- pa_mute_control_release(control->mute_control);
-
- if (control->own_control && control->mute_control && !control->mute_control->persistent)
- pa_mute_control_free(control->mute_control);
- break;
- }
-
- pa_xfree(control);
-}
-
-static void control_set_master(struct control *control, struct control *master) {
- struct control *old_master;
-
- pa_assert(control);
- pa_assert(!master || master->type == control->type);
-
- old_master = control->master;
-
- if (master == old_master)
- return;
-
- if (old_master) {
- control_remove_slave(old_master, control);
- control->synced_with_master = false;
- }
-
- control->master = master;
-
- if (master) {
- control_add_slave(master, control);
-
- switch (control->type) {
- case CONTROL_TYPE_VOLUME:
- pa_volume_control_set_volume(control->volume_control, &master->volume_control->volume, true, true);
- break;
-
- case CONTROL_TYPE_MUTE:
- pa_mute_control_set_mute(control->mute_control, master->mute_control->mute);
- break;
- }
-
- control->synced_with_master = true;
- }
-}
-
-static void control_add_slave(struct control *control, struct control *slave) {
- pa_assert(control);
- pa_assert(slave);
-
- pa_assert_se(pa_hashmap_put(control->slaves, slave, slave) >= 0);
-}
-
-static void control_remove_slave(struct control *control, struct control *slave) {
- pa_assert(control);
- pa_assert(slave);
-
- pa_assert_se(pa_hashmap_remove(control->slaves, slave));
-}
-
-static int group_new(struct userdata *u, const char *name, struct group **_r) {
- struct group *group = NULL;
- int r;
- struct group *slave;
- struct stream_rule *rule;
- void *state;
-
- pa_assert(u);
- pa_assert(name);
- pa_assert(_r);
-
- group = pa_xnew0(struct group, 1);
- group->userdata = u;
-
- r = pa_audio_group_new(u->volume_api, name, &group->audio_group);
- if (r < 0)
- goto fail;
-
- group->volume_slaves = pa_hashmap_new(NULL, NULL);
- group->mute_slaves = pa_hashmap_new(NULL, NULL);
- group->volume_stream_rules = pa_hashmap_new(NULL, NULL);
- group->mute_stream_rules = pa_hashmap_new(NULL, NULL);
-
- PA_HASHMAP_FOREACH(slave, u->groups, state) {
- if (slave == group)
- continue;
-
- if (pa_safe_streq(slave->volume_master_name, group->audio_group->name))
- group_set_master(slave, CONTROL_TYPE_VOLUME, group);
-
- if (pa_safe_streq(slave->mute_master_name, group->audio_group->name))
- group_set_master(slave, CONTROL_TYPE_MUTE, group);
- }
-
- PA_HASHMAP_FOREACH(rule, u->stream_rules, state) {
- if (pa_safe_streq(rule->audio_group_name_for_volume, group->audio_group->name))
- stream_rule_set_group(rule, CONTROL_TYPE_VOLUME, group);
-
- if (pa_safe_streq(rule->audio_group_name_for_mute, group->audio_group->name))
- stream_rule_set_group(rule, CONTROL_TYPE_MUTE, group);
- }
-
- *_r = group;
- return 0;
-
-fail:
- if (group)
- group_free(group);
-
- return r;
-}
-
-static void group_put(struct group *group) {
- pa_assert(group);
-
- pa_audio_group_put(group->audio_group);
-
- if (group->volume_control)
- control_put(group->volume_control);
-
- if (group->mute_control)
- control_put(group->mute_control);
-}
-
-static void group_unlink(struct group *group) {
- struct stream_rule *rule;
- struct group *slave;
- void *state;
-
- pa_assert(group);
-
- if (group->unlinked)
- return;
-
- group->unlinked = true;
-
- PA_HASHMAP_FOREACH(rule, group->volume_stream_rules, state)
- stream_rule_set_group(rule, CONTROL_TYPE_VOLUME, NULL);
-
- PA_HASHMAP_FOREACH(rule, group->mute_stream_rules, state)
- stream_rule_set_group(rule, CONTROL_TYPE_MUTE, NULL);
-
- PA_HASHMAP_FOREACH(slave, group->volume_slaves, state)
- group_set_master(slave, CONTROL_TYPE_VOLUME, NULL);
-
- PA_HASHMAP_FOREACH(slave, group->mute_slaves, state)
- group_set_master(slave, CONTROL_TYPE_MUTE, NULL);
-
- group_disable_control(group, CONTROL_TYPE_MUTE);
- group_disable_control(group, CONTROL_TYPE_VOLUME);
-
- if (group->audio_group)
- pa_audio_group_unlink(group->audio_group);
-}
-
-static void group_free(struct group *group) {
- pa_assert(group);
-
- group_unlink(group);
-
- if (group->mute_stream_rules) {
- pa_assert(pa_hashmap_isempty(group->mute_stream_rules));
- pa_hashmap_free(group->mute_stream_rules);
- }
-
- if (group->volume_stream_rules) {
- pa_assert(pa_hashmap_isempty(group->volume_stream_rules));
- pa_hashmap_free(group->volume_stream_rules);
- }
-
- if (group->mute_slaves) {
- pa_assert(pa_hashmap_isempty(group->mute_slaves));
- pa_hashmap_free(group->mute_slaves);
- }
-
- if (group->volume_slaves) {
- pa_assert(pa_hashmap_isempty(group->volume_slaves));
- pa_hashmap_free(group->volume_slaves);
- }
-
- pa_assert(!group->mute_master_name);
- pa_assert(!group->volume_master_name);
- pa_assert(!group->mute_master);
- pa_assert(!group->volume_master);
- pa_assert(!group->mute_control);
- pa_assert(!group->volume_control);
-
- if (group->audio_group)
- pa_audio_group_free(group->audio_group);
-
- pa_xfree(group);
-}
-
-static void group_set_own_control_name(struct group *group, enum control_type type, const char *name) {
- struct group *slave;
- void *state;
-
- pa_assert(group);
-
- if (name)
- group_set_master_name(group, type, NULL);
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- if (pa_safe_streq(name, group->own_volume_control_name))
- return;
-
- if (group->volume_control) {
- control_free(group->volume_control);
- group->volume_control = NULL;
- }
-
- pa_xfree(group->own_volume_control_name);
- group->own_volume_control_name = pa_xstrdup(name);
-
- if (name) {
- control_new_for_group(group, CONTROL_TYPE_VOLUME, name, true, &group->volume_control);
-
- PA_HASHMAP_FOREACH(slave, group->volume_slaves, state) {
- if (slave->volume_control)
- control_set_master(slave->volume_control, group->volume_control);
- }
- }
- break;
-
- case CONTROL_TYPE_MUTE:
- if (pa_safe_streq(name, group->own_mute_control_name))
- return;
-
- if (group->mute_control) {
- control_free(group->mute_control);
- group->mute_control = NULL;
- }
-
- pa_xfree(group->own_mute_control_name);
- group->own_mute_control_name = pa_xstrdup(name);
-
- if (name) {
- control_new_for_group(group, CONTROL_TYPE_MUTE, name, true, &group->mute_control);
-
- PA_HASHMAP_FOREACH(slave, group->mute_slaves, state) {
- if (slave->mute_control)
- control_set_master(slave->mute_control, group->mute_control);
- }
- }
- break;
- }
-}
-
-static void group_set_master(struct group *group, enum control_type type, struct group *master) {
- struct group *old_master;
- struct control *master_control = NULL;
-
- pa_assert(group);
- pa_assert(master != group);
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- old_master = group->volume_master;
-
- if (master == old_master)
- return;
-
- if (old_master)
- group_remove_slave(old_master, CONTROL_TYPE_VOLUME, group);
-
- group->volume_master = master;
-
- if (master)
- group_add_slave(master, CONTROL_TYPE_VOLUME, group);
-
- if (group->volume_control) {
- if (master)
- master_control = master->volume_control;
-
- control_set_master(group->volume_control, master_control);
- }
- break;
-
- case CONTROL_TYPE_MUTE:
- old_master = group->mute_master;
-
- if (master == old_master)
- return;
-
- if (old_master)
- group_remove_slave(old_master, CONTROL_TYPE_MUTE, group);
-
- group->mute_master = master;
-
- if (master)
- group_add_slave(master, CONTROL_TYPE_MUTE, group);
-
- if (group->mute_control) {
- if (master)
- master_control = master->volume_control;
-
- control_set_master(group->volume_control, master_control);
- }
- break;
- }
-}
-
-static int group_set_master_name(struct group *group, enum control_type type, const char *name) {
- struct group *slave;
- void *state;
- struct group *master = NULL;
-
- pa_assert(group);
-
- if (pa_safe_streq(name, group->audio_group->name)) {
- pa_log("Can't bind audio group control to itself.");
- return -PA_ERR_INVALID;
- }
-
- if (name)
- group_set_own_control_name(group, type, NULL);
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- if (pa_safe_streq(name, group->volume_master_name))
- return 0;
-
- pa_xfree(group->volume_master_name);
- group->volume_master_name = pa_xstrdup(name);
-
- if (name && !group->volume_control) {
- control_new_for_group(group, CONTROL_TYPE_VOLUME, "audio-group-volume-control", false, &group->volume_control);
-
- PA_HASHMAP_FOREACH(slave, group->volume_slaves, state) {
- if (slave->volume_control)
- control_set_master(slave->volume_control, group->volume_control);
- }
-
- } else if (!name && group->volume_control) {
- control_free(group->volume_control);
- group->volume_control = NULL;
- }
- break;
-
- case CONTROL_TYPE_MUTE:
- if (pa_safe_streq(name, group->mute_master_name))
- return 0;
-
- pa_xfree(group->mute_master_name);
- group->mute_master_name = pa_xstrdup(name);
-
- if (name && !group->mute_control) {
- control_new_for_group(group, CONTROL_TYPE_MUTE, "audio-group-mute-control", false, &group->mute_control);
-
- PA_HASHMAP_FOREACH(slave, group->mute_slaves, state) {
- if (slave->mute_control)
- control_set_master(slave->mute_control, group->mute_control);
- }
-
- } else if (!name && group->mute_control) {
- control_free(group->mute_control);
- group->mute_control = NULL;
- }
- break;
- }
-
- if (name)
- master = pa_hashmap_get(group->userdata->groups, name);
-
- group_set_master(group, type, master);
-
- return 0;
-}
-
-static void group_disable_control(struct group *group, enum control_type type) {
- pa_assert(group);
-
- group_set_own_control_name(group, type, NULL);
- group_set_master_name(group, type, NULL);
-}
-
-static void group_add_slave(struct group *group, enum control_type type, struct group *slave) {
- pa_assert(group);
- pa_assert(slave);
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- pa_assert_se(pa_hashmap_put(group->volume_slaves, slave, slave) >= 0);
- break;
-
- case CONTROL_TYPE_MUTE:
- pa_assert_se(pa_hashmap_put(group->mute_slaves, slave, slave) >= 0);
- break;
- }
-}
-
-static void group_remove_slave(struct group *group, enum control_type type, struct group *slave) {
- pa_assert(group);
- pa_assert(slave);
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- pa_assert_se(pa_hashmap_remove(group->volume_slaves, slave));
- break;
-
- case CONTROL_TYPE_MUTE:
- pa_assert_se(pa_hashmap_remove(group->mute_slaves, slave));
- }
-}
-
-static void group_add_stream_rule(struct group *group, enum control_type type, struct stream_rule *rule) {
- pa_assert(group);
- pa_assert(rule);
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- pa_assert_se(pa_hashmap_put(group->volume_stream_rules, rule, rule) >= 0);
- break;
-
- case CONTROL_TYPE_MUTE:
- pa_assert_se(pa_hashmap_put(group->mute_stream_rules, rule, rule) >= 0);
- break;
- }
-}
-
-static void group_remove_stream_rule(struct group *group, enum control_type type, struct stream_rule *rule) {
- pa_assert(group);
- pa_assert(rule);
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- pa_assert_se(pa_hashmap_remove(group->volume_stream_rules, rule));
- break;
-
- case CONTROL_TYPE_MUTE:
- pa_assert_se(pa_hashmap_remove(group->mute_stream_rules, rule));
- break;
- }
-}
-
-static struct stream_rule *stream_rule_new(struct userdata *u, const char *name) {
- struct stream_rule *rule;
-
- pa_assert(u);
- pa_assert(name);
-
- rule = pa_xnew0(struct stream_rule, 1);
- rule->userdata = u;
- rule->name = pa_xstrdup(name);
- rule->direction = match_direction_unknown;
- rule->match_expression = expression_new();
-
- return rule;
-}
-
-static void stream_rule_free(struct stream_rule *rule) {
- pa_assert(rule);
-
- if (rule->match_expression)
- expression_free(rule->match_expression);
-
- stream_rule_set_group_name(rule, CONTROL_TYPE_MUTE, NULL);
- stream_rule_set_group_name(rule, CONTROL_TYPE_VOLUME, NULL);
- pa_xfree(rule->name);
- pa_xfree(rule);
-}
-
-static void stream_rule_set_match_expression(struct stream_rule *rule, struct expression *expression) {
- pa_assert(rule);
- pa_assert(expression);
-
- if (rule->match_expression)
- expression_free(rule->match_expression);
-
- rule->match_expression = expression;
-}
-
-static void stream_rule_set_group(struct stream_rule *rule, enum control_type type, struct group *group) {
- pa_assert(rule);
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- if (group == rule->group_for_volume)
- return;
-
- if (rule->group_for_volume)
- group_remove_stream_rule(rule->group_for_volume, CONTROL_TYPE_VOLUME, rule);
-
- rule->group_for_volume = group;
-
- if (group)
- group_add_stream_rule(group, CONTROL_TYPE_VOLUME, rule);
- break;
-
- case CONTROL_TYPE_MUTE:
- if (group == rule->group_for_mute)
- return;
-
- if (rule->group_for_mute)
- group_remove_stream_rule(rule->group_for_mute, CONTROL_TYPE_MUTE, rule);
-
- rule->group_for_mute = group;
-
- if (group)
- group_add_stream_rule(group, CONTROL_TYPE_MUTE, rule);
- break;
- }
-}
-
-static void stream_rule_set_group_name(struct stream_rule *rule, enum control_type type, const char *name) {
- struct group *group = NULL;
-
- pa_assert(rule);
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- pa_xfree(rule->audio_group_name_for_volume);
- rule->audio_group_name_for_volume = pa_xstrdup(name);
- break;
-
- case CONTROL_TYPE_MUTE:
- pa_xfree(rule->audio_group_name_for_mute);
- rule->audio_group_name_for_mute = pa_xstrdup(name);
- break;
- }
-
- if (name)
- group = pa_hashmap_get(rule->userdata->groups, name);
-
- stream_rule_set_group(rule, type, group);
-}
-
-static bool stream_rule_match(struct stream_rule *rule, pas_stream *stream) {
- struct conjunction *c;
-
- PA_LLIST_FOREACH(c, rule->match_expression->conjunctions) {
- struct literal *l;
- bool and_success = true;
- PA_LLIST_FOREACH(l, c->literals) {
- if (!literal_match(l, stream)) {
- /* at least one fail for conjunction */
- and_success = false;
- break;
- }
- }
-
- if (and_success) {
- /* at least one match for disjunction */
- return true;
- }
- }
-
- /* no matches */
- return false;
-}
-
-/* stream classification */
-
-static bool literal_match(struct literal *literal, pas_stream *stream) {
-
- if (literal->stream_direction != match_direction_unknown) {
- /* check the stream direction; _sink inputs_ are always _outputs_ */
-
- if ((stream->direction == PA_DIRECTION_OUTPUT && literal->stream_direction == match_direction_output) ||
- (stream->direction == PA_DIRECTION_INPUT && literal->stream_direction == match_direction_input)) {
- return literal->negation ? false : true;
- }
- }
- else if (literal->property_name && literal->property_value) {
- /* check the property from the property list */
-
- if (pa_proplist_contains(stream->proplist, literal->property_name)) {
- const char *prop = pa_proplist_gets(stream->proplist, literal->property_name);
-
- if (prop && strcmp(prop, literal->property_value) == 0)
- return literal->negation ? false : true;
- }
- }
-
- /* no match */
- return literal->negation ? true : false;
-}
-
-static pa_hook_result_t stream_put_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pas_stream *stream = call_data;
- struct stream_rule *rule;
- unsigned idx;
-
- pa_assert(u);
- pa_assert(stream);
-
- PA_DYNARRAY_FOREACH(rule, u->stream_rules_list, idx) {
- if (stream_rule_match(rule, stream)) {
- pa_hashmap_put(u->rules_by_stream, stream, rule);
- break;
- }
- }
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t stream_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pas_stream *stream = call_data;
-
- pa_assert(u);
- pa_assert(stream);
-
- pa_hashmap_remove(u->rules_by_stream, stream);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t volume_control_implementation_initialized_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_volume_control *volume_control = call_data;
- struct control *control;
-
- pa_assert(u);
- pa_assert(volume_control);
-
- if (volume_control->purpose != PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME)
- return PA_HOOK_OK;
-
- control = control_new_for_stream(u, CONTROL_TYPE_VOLUME, volume_control->owner_stream);
- control_put(control);
- pa_assert_se(pa_hashmap_put(u->stream_volume_controls, volume_control->owner_stream, control) >= 0);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t mute_control_implementation_initialized_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_mute_control *mute_control = call_data;
- struct control *control;
-
- pa_assert(u);
- pa_assert(mute_control);
-
- if (mute_control->purpose != PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE)
- return PA_HOOK_OK;
-
- control = control_new_for_stream(u, CONTROL_TYPE_MUTE, mute_control->owner_stream);
- control_put(control);
- pa_assert_se(pa_hashmap_put(u->stream_mute_controls, mute_control->owner_stream, control) >= 0);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t volume_control_set_initial_volume_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_volume_control *volume_control = call_data;
- struct stream_rule *rule;
- struct control *control;
-
- pa_assert(u);
- pa_assert(volume_control);
-
- if (volume_control->purpose != PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME)
- return PA_HOOK_OK;
-
- rule = pa_hashmap_get(u->rules_by_stream, volume_control->owner_stream);
- if (!rule)
- return PA_HOOK_OK;
-
- if (!rule->group_for_volume)
- return PA_HOOK_OK;
-
- if (!rule->group_for_volume->volume_control)
- return PA_HOOK_OK;
-
- control = pa_hashmap_get(u->stream_volume_controls, volume_control->owner_stream);
- pa_assert(control);
- pa_assert(control->volume_control == volume_control);
-
- /* This will set the volume for volume_control. */
- control_set_master(control, rule->group_for_volume->volume_control);
-
- return PA_HOOK_STOP;
-}
-
-static pa_hook_result_t mute_control_set_initial_mute_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_mute_control *mute_control = call_data;
- struct stream_rule *rule;
- struct control *control;
-
- pa_assert(u);
- pa_assert(mute_control);
-
- if (mute_control->purpose != PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE)
- return PA_HOOK_OK;
-
- rule = pa_hashmap_get(u->rules_by_stream, mute_control->owner_stream);
- if (!rule)
- return PA_HOOK_OK;
-
- if (!rule->group_for_mute)
- return PA_HOOK_OK;
-
- if (!rule->group_for_mute->mute_control)
- return PA_HOOK_OK;
-
- control = pa_hashmap_get(u->stream_mute_controls, mute_control->owner_stream);
- pa_assert(control);
- pa_assert(control->mute_control == mute_control);
-
- /* This will set the mute for mute_control. */
- control_set_master(control, rule->group_for_mute->mute_control);
-
- return PA_HOOK_STOP;
-}
-
-static pa_hook_result_t volume_control_volume_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_volume_control *volume_control = call_data;
- struct control *control;
-
- pa_assert(u);
- pa_assert(volume_control);
-
- if (volume_control->purpose != PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME)
- return PA_HOOK_OK;
-
- control = pa_hashmap_get(u->stream_volume_controls, volume_control->owner_stream);
- if (!control)
- return PA_HOOK_OK;
-
- if (!control->master)
- return PA_HOOK_OK;
-
- pa_volume_control_set_volume(control->master->volume_control, &volume_control->volume, true, true);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t mute_control_mute_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_mute_control *mute_control = call_data;
- struct control *control;
-
- pa_assert(u);
- pa_assert(mute_control);
-
- if (mute_control->purpose != PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE)
- return PA_HOOK_OK;
-
- control = pa_hashmap_get(u->stream_mute_controls, mute_control->owner_stream);
- if (!control)
- return PA_HOOK_OK;
-
- if (!control->master)
- return PA_HOOK_OK;
-
- pa_mute_control_set_mute(control->master->mute_control, mute_control->mute);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t volume_control_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_volume_control *volume_control = call_data;
- struct control *control;
-
- pa_assert(u);
- pa_assert(volume_control);
-
- if (volume_control->purpose != PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME)
- return PA_HOOK_OK;
-
- control = pa_hashmap_remove(u->stream_volume_controls, volume_control->owner_stream);
- if (!control)
- return PA_HOOK_OK;
-
- control_free(control);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t mute_control_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_mute_control *mute_control = call_data;
- struct control *control;
-
- pa_assert(u);
- pa_assert(mute_control);
-
- if (mute_control->purpose != PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE)
- return PA_HOOK_OK;
-
- control = pa_hashmap_remove(u->stream_mute_controls, mute_control->owner_stream);
- if (!control)
- return PA_HOOK_OK;
-
- control_free(control);
-
- return PA_HOOK_OK;
-}
-
-/* parser for configuration file */
-
-/*
- Parse the match expression. The syntax is this:
-
- OPER := "AND" | "OR"
- OPEN_BRACE := "("
- CLOSE_BRACE := ")"
- EXPR := OPEN_BRACE EXPR OPER EXPR CLOSE_BRACE | VAR
- VAR := LIT | "NEG" LIT
- LIT := PREDICATE (defined by rule semantics)
-
- In addition there is a requirement that the expressions need to be in
- disjunctive normal form. It means that if there is an expression that
- has AND operator, there may not be any OR operators in its subexpressions.
-
- Example expressions:
-
- (foo)
- (foo AND bar)
- (foo OR (bar AND xxx))
- (NEG foo OR (bar AND NEG xxx))
-
- The predicate here is the single rule that is matched against the new sink
- input. The syntax is this:
-
- PREDICATE := "direction" DIRECTION | "property" PROPERTY
- DIRECTION := "input" | "output"
- PROPERTY := PROPERTY_NAME "=" PROPERTY_VALUE
- PROPERTY_NAME := STRING
- PROPERTY_VALUE := STRING
-
- The allowed characters for STRING are standard ascii characters. Not
- allowed substrings are the reserved words "AND", "OR", "(", ")", "NEG" and
- "=".
-
- Complete examples:
-
- (property application.process.binary=paplay)
-
- (property media.role=music AND direction input)
-
- (property application.process.binary=paplay OR (direction input OR direction output))
-*/
-
-#if 0
-static void print_literal(struct literal *l) {
- if (l->stream_direction != match_direction_unknown) {
- pa_log_info(" %sstream direction %s",
- l->negation ? "NEG " : "",
- l->stream_direction == match_direction_input ? "input" : "output");
- }
- else {
- pa_log_info(" %sproperty %s == %s",
- l->negation ? "NEG " : "",
- l->property_name ? l->property_name : "NULL",
- l->property_value ? l->property_value : "NULL");
- }
-}
-
-static void print_conjunction(struct conjunction *c) {
- struct literal *l;
- pa_log_info(" conjunction for literals:");
- PA_LLIST_FOREACH(l, c->literals) {
- print_literal(l);
- }
-}
-
-static void print_expression(struct expression *e) {
- struct conjunction *c;
- pa_log_info("disjunction for conjunctions:");
- PA_LLIST_FOREACH(c, e->conjunctions) {
- print_conjunction(c);
- }
-}
-#endif
-
-static void delete_literal(struct literal *l) {
-
- if (!l)
- return;
-
- pa_xfree(l->property_name);
- pa_xfree(l->property_value);
- pa_xfree(l);
-}
-
-static void delete_conjunction(struct conjunction *c) {
- struct literal *l;
-
- if (!c)
- return;
-
- PA_LLIST_FOREACH(l, c->literals) {
- delete_literal(l);
- }
-
- pa_xfree(c);
-}
-
-static struct expression *expression_new(void) {
- struct expression *expression;
-
- expression = pa_xnew0(struct expression, 1);
-
- return expression;
-}
-
-static void expression_free(struct expression *expression) {
- struct conjunction *c;
-
- pa_assert(expression);
-
- PA_LLIST_FOREACH(c, expression->conjunctions)
- delete_conjunction(c);
-
- pa_xfree(expression);
-}
-
-enum logic_operator {
- operator_not_set = 0,
- operator_and,
- operator_or,
-};
-
-struct expression_token {
- struct expression_token *left;
- struct expression_token *right;
-
- enum logic_operator oper;
-
- struct literal_token *lit;
-};
-
-struct literal_token {
- bool negation;
- char *var;
-};
-
-static void delete_literal_token(struct literal_token *l) {
-
- if (!l)
- return;
-
- pa_xfree(l->var);
- pa_xfree(l);
-}
-
-static void delete_expression_token(struct expression_token *e) {
-
- if (!e)
- return;
-
- delete_expression_token(e->left);
- delete_expression_token(e->right);
- delete_literal_token(e->lit);
-
- e->left = NULL;
- e->right = NULL;
- e->lit = NULL;
-
- pa_xfree(e);
-}
-
-static struct expression_token *parse_rule_internal(const char *rule, bool disjunction_allowed) {
-
- int len = strlen(rule);
- struct expression_token *et;
- char *p;
- int brace_count = 0;
- bool braces_present = false;
- char left_buf[len+1];
- char right_buf[len+1];
-
- et = pa_xnew0(struct expression_token, 1);
-
- if (!et)
- return NULL;
-
- /* count the braces -- we want to find the case when there is only one brace open */
-
- p = (char *) rule;
-
- while (*p) {
- if (*p == '(') {
- braces_present = true;
- brace_count++;
- }
- else if (*p == ')') {
- brace_count--;
- }
-
- if (brace_count == 1) {
-
- /* the parser is recursive and just goes down the tree on the
- * topmost level (where the brace count is 1). If there are no
- * braces this is a literal */
-
- /* find the operator AND or OR */
-
- if (strncmp(p, "AND", 3) == 0) {
-
- /* copy parts */
- char *begin_left = (char *) rule+1;
- char *begin_right = p+3;
-
- int left_len = p - rule - 1; /* minus '(' */
- int right_len = len - 3 - left_len - 2; /* minus AND and '(' and ')'*/
-
- memcpy(left_buf, begin_left, left_len);
- left_buf[left_len] = '\0';
- memcpy(right_buf, begin_right, right_len);
- right_buf[right_len] = '\0';
-
- et->left = parse_rule_internal(left_buf, false);
- et->right = parse_rule_internal(right_buf, false);
- et->oper = operator_and;
-
- if (!et->left || !et->right) {
- delete_expression_token(et);
- return NULL;
- }
-
- return et;
- }
- else if (strncmp(p, "OR", 2) == 0) {
-
- char *begin_left = (char *) rule+1;
- char *begin_right = p+2;
-
- int left_len = p - rule - 1; /* minus '(' */
- int right_len = len - 2 - left_len - 2; /* minus OR and '(' and ')'*/
-
- if (!disjunction_allowed) {
- pa_log_error("logic expression not in dnf");
- delete_expression_token(et);
- return NULL;
- }
-
- memcpy(left_buf, begin_left, left_len);
- left_buf[left_len] = '\0';
- memcpy(right_buf, begin_right, right_len);
- right_buf[right_len] = '\0';
-
- et->left = parse_rule_internal(left_buf, true);
- et->right = parse_rule_internal(right_buf, true);
- et->oper = operator_or;
-
- if (!et->left || !et->right) {
- delete_expression_token(et);
- return NULL;
- }
-
- return et;
- }
- /* else a literal which is inside braces */
- }
-
- p++;
- }
-
- if (brace_count != 0) {
- /* the input is not valid */
- pa_log_error("mismatched braces in logic expression");
- delete_expression_token(et);
- return NULL;
- }
- else {
- /* this is a literal */
- char *begin_lit;
- char buf[len+1];
- struct literal_token *lit = pa_xnew0(struct literal_token, 1);
-
- if (!lit) {
- delete_expression_token(et);
- return NULL;
- }
-
- if (braces_present) {
- /* remove all braces */
- char *k;
- char *l;
-
- k = (char *) rule;
- l = buf;
-
- while (*k) {
- if (*k == '(' || *k == ')') {
- k++;
- continue;
- }
-
- *l = *k;
- l++;
- k++;
- }
- *l = '\0';
- }
- else {
- strncpy(buf, rule, len);
- buf[len] = '\0';
- }
-
- if (strncmp(buf, "NEG", 3) == 0) {
- begin_lit = (char *) buf + 3;
- lit->negation = true;
- }
- else {
- begin_lit = (char *) buf;
- lit->negation = false;
- }
-
- lit->var = pa_xstrdup(begin_lit);
-
- et->lit = lit;
- }
-
- return et;
-}
-
-static bool gather_literal(struct expression_token *et, struct literal *l) {
-#define PROPERTY_KEYWORD "property"
-#define DIRECTION_KEYWORD "direction"
-#define DIRECTION_VALUE_INPUT "input"
-#define DIRECTION_VALUE_OUTPUT "output"
-
- char *p = et->lit->var;
- int len = strlen(et->lit->var);
-
- l->negation = et->lit->negation;
-
- if (strncmp(p, PROPERTY_KEYWORD, strlen(PROPERTY_KEYWORD)) == 0) {
- char name[len];
- char value[len];
- int i = 0;
-
- p += strlen(PROPERTY_KEYWORD);
-
- /* parse the property pair: name=value */
-
- while (*p && *p != '=') {
- name[i++] = *p;
- p++;
- }
-
- /* check if we really found '=' */
-
- if (*p != '=') {
- pa_log_error("property syntax broken for '%s'", et->lit->var);
- goto error;
- }
-
- name[i] = '\0';
-
- p++;
- i = 0;
-
- while (*p) {
- value[i++] = *p;
- p++;
- }
-
- value[i] = '\0';
-
- l->property_name = pa_xstrdup(name);
- l->property_value = pa_xstrdup(value);
- }
- else if (strncmp(p, DIRECTION_KEYWORD, strlen(DIRECTION_KEYWORD)) == 0) {
- p += strlen(DIRECTION_KEYWORD);
-
- if (strncmp(p, DIRECTION_VALUE_INPUT, strlen(DIRECTION_VALUE_INPUT)) == 0) {
- l->stream_direction = match_direction_input;
- }
- else if (strncmp(p, DIRECTION_VALUE_OUTPUT, strlen(DIRECTION_VALUE_OUTPUT)) == 0) {
- l->stream_direction = match_direction_output;
- }
- else {
- pa_log_error("unknown direction(%s): %s", et->lit->var, p);
- goto error;
- }
- }
- else {
- pa_log_error("not able to parse the value: '%s'", et->lit->var);
- goto error;
- }
-
- return true;
-
-error:
- return false;
-
-#undef DIRECTION_VALUE_OUTPUT
-#undef DIRECTION_VALUE_INPUT
-#undef DIRECTION_KEYWORD
-#undef PROPERTY_KEYWORD
-}
-
-static bool gather_conjunction(struct expression_token *et, struct conjunction *c) {
-
- if (et->oper == operator_and) {
- if (!gather_conjunction(et->left, c) ||
- !gather_conjunction(et->right, c)) {
- return false;
- }
- }
- else {
- /* literal */
- struct literal *l = pa_xnew0(struct literal, 1);
-
- if (!l)
- return false;
-
- if (!gather_literal(et, l)) {
- pa_log_error("audio groups config: literal parsing failed");
- delete_literal(l);
- return false;
- }
-
- PA_LLIST_INIT(struct literal, l);
- PA_LLIST_PREPEND(struct literal, c->literals, l);
- }
-
- return true;
-}
-
-static bool gather_expression(struct expression *e, struct expression_token *et) {
-
- if (et->oper == operator_or) {
- if (!gather_expression(e, et->right) ||
- !gather_expression(e, et->left))
- return false;
- }
- else {
- /* conjunction or literal */
- struct conjunction *c = pa_xnew0(struct conjunction, 1);
-
- if (!c)
- return false;
-
- PA_LLIST_HEAD_INIT(struct literal, c->literals);
-
- if (!gather_conjunction(et, c)) {
- delete_conjunction(c);
- return false;
- }
-
- PA_LLIST_INIT(struct conjunction, c);
- PA_LLIST_PREPEND(struct conjunction, e->conjunctions, c);
- }
-
- return true;
-}
-
-static int expression_from_string(const char *str, struct expression **_r) {
- const char *k;
- char *l;
- struct expression *e = NULL;
- char *buf = NULL;
- struct expression_token *et = NULL;
-
- pa_assert(str);
- pa_assert(_r);
-
- buf = pa_xmalloc0(strlen(str) + 1);
-
- /* remove whitespace */
-
- k = str;
- l = buf;
-
- while (*k) {
- if (*k == ' ') {
- k++;
- continue;
- }
-
- *l = *k;
- l++;
- k++;
- }
-
- /* et is the root of an expression tree */
- et = parse_rule_internal(buf, true);
-
- if (!et)
- goto error;
-
- e = pa_xnew0(struct expression, 1);
-
- PA_LLIST_HEAD_INIT(struct conjunction, e->conjunctions);
-
- /* gather expressions to actual match format */
- if (!gather_expression(e, et)) {
- /* gathering the expression from tokens went wrong */
- pa_log_error("failed to parse audio group stream classification data");
- goto error;
- }
-
-#if 0
- print_expression(e);
-#endif
-
- /* free memory */
- delete_expression_token(et);
- pa_xfree(buf);
-
- *_r = e;
- return 0;
-
-error:
- delete_expression_token(et);
- pa_xfree(buf);
- expression_free(e);
-
- return -PA_ERR_INVALID;
-}
-
-static int parse_streams(pa_config_parser_state *state) {
- struct userdata *u;
- char *name;
- const char *split_state = NULL;
-
- pa_assert(state);
-
- u = state->userdata;
-
- while ((name = pa_split_spaces(state->rvalue, &split_state))) {
- const char *name2;
- unsigned idx;
- bool duplicate = false;
-
- /* Avoid adding duplicates in u->stream_rule_names. */
- PA_DYNARRAY_FOREACH(name2, u->stream_rule_names, idx) {
- if (pa_streq(name, name2)) {
- duplicate = true;
- break;
- }
- }
-
- if (duplicate) {
- pa_xfree(name);
- continue;
- }
-
- pa_dynarray_append(u->stream_rule_names, name);
- }
-
- return 0;
-}
-
-static int parse_group_control(pa_config_parser_state *state, struct group *group, enum control_type type) {
- pa_assert(state);
- pa_assert(group);
-
- if (pa_streq(state->rvalue, NONE_KEYWORD))
- group_disable_control(group, type);
-
- else if (pa_startswith(state->rvalue, CREATE_PREFIX))
- group_set_own_control_name(group, type, state->rvalue + strlen(CREATE_PREFIX));
-
- else if (pa_startswith(state->rvalue, BIND_PREFIX)) {
- if (pa_startswith(state->rvalue, BIND_AUDIO_GROUP_PREFIX)) {
- int r;
-
- r = group_set_master_name(group, type, state->rvalue + strlen(BIND_AUDIO_GROUP_PREFIX));
- if (r < 0) {
- pa_log("[%s:%u] Failed to set binding target \"%s\".", state->filename, state->lineno, state->rvalue + strlen(BIND_PREFIX));
- return r;
- }
- } else {
- pa_log("[%s:%u] Failed to parse binding target \"%s\".", state->filename, state->lineno, state->rvalue + strlen(BIND_PREFIX));
- return -PA_ERR_INVALID;
- }
- } else {
- pa_log("[%s:%u] Failed to parse value \"%s\".", state->filename, state->lineno, state->rvalue);
- return -PA_ERR_INVALID;
- }
-
- return 0;
-}
-
-static int parse_common(pa_config_parser_state *state) {
- char *section;
- struct userdata *u = state->userdata;
- const char *name;
- int r;
-
- pa_assert(state);
-
- section = state->section;
- if (!section) {
- pa_log("[%s:%u] Lvalue \"%s\" not expected in the General section.", state->filename, state->lineno, state->lvalue);
- return -PA_ERR_INVALID;
- }
-
- if (pa_startswith(section, AUDIOGROUP_START)) {
- struct group *group;
-
- name = section + strlen(AUDIOGROUP_START);
-
- group = pa_hashmap_get(u->groups, name);
- if (!group) {
- r = group_new(u, name, &group);
- if (r < 0) {
- pa_log("[%s:%u] Failed to create an audio group with name \"%s\".", state->filename, state->lineno, name);
- return r;
- }
-
- pa_hashmap_put(u->groups, (void *) group->audio_group->name, group);
- }
-
- if (pa_streq(state->lvalue, "description"))
- pa_audio_group_set_description(group->audio_group, state->rvalue);
-
- else if (pa_streq(state->lvalue, "volume-control"))
- return parse_group_control(state, group, CONTROL_TYPE_VOLUME);
-
- else if (pa_streq(state->lvalue, "mute-control"))
- return parse_group_control(state, group, CONTROL_TYPE_MUTE);
-
- else {
- pa_log("[%s:%u] Lvalue \"%s\" not expected in the AudioGroup section.", state->filename, state->lineno, state->lvalue);
- return -PA_ERR_INVALID;
- }
- }
- else if (pa_startswith(section, STREAM_RULE_START)) {
- struct stream_rule *rule;
-
- name = section + strlen(STREAM_RULE_START);
-
- rule = pa_hashmap_get(u->stream_rules, name);
- if (!rule) {
- rule = stream_rule_new(u, name);
- pa_hashmap_put(u->stream_rules, rule->name, rule);
- }
-
- if (pa_streq(state->lvalue, "audio-group-for-volume"))
- stream_rule_set_group_name(rule, CONTROL_TYPE_VOLUME, state->rvalue);
-
- else if (pa_streq(state->lvalue, "audio-group-for-mute"))
- stream_rule_set_group_name(rule, CONTROL_TYPE_MUTE, state->rvalue);
-
- else if (pa_streq(state->lvalue, "match")) {
- struct expression *expression;
-
- r = expression_from_string(state->rvalue, &expression);
- if (r < 0) {
- pa_log("[%s:%u] Failed to parse value \"%s\".", state->filename, state->lineno, state->rvalue);
- return r;
- }
-
- stream_rule_set_match_expression(rule, expression);
- }
- }
-
- return 0;
-}
-
-int pa__init(pa_module *module) {
- pa_modargs *ma = NULL;
- struct userdata *u;
- FILE *f;
- char *fn = NULL;
- struct group *group;
- void *state;
- const char *name;
- unsigned idx;
-
- pa_assert(module);
-
- if (!(ma = pa_modargs_new(module->argument, valid_modargs))) {
- pa_log("Failed to parse module arguments");
- goto fail;
- }
-
- u = module->userdata = pa_xnew0(struct userdata, 1);
- u->volume_api = pa_volume_api_get(module->core);
- u->groups = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
- (pa_free_cb_t) group_free);
- u->stream_rules = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
- (pa_free_cb_t) stream_rule_free);
- u->stream_rules_list = pa_dynarray_new(NULL);
- u->rules_by_stream = pa_hashmap_new(NULL, NULL);
- u->stream_volume_controls = pa_hashmap_new_full(NULL, NULL, NULL, (pa_free_cb_t) control_free);
- u->stream_mute_controls = pa_hashmap_new_full(NULL, NULL, NULL, (pa_free_cb_t) control_free);
- u->stream_put_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_PUT], PA_HOOK_NORMAL, stream_put_cb,
- u);
- u->stream_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_UNLINK], PA_HOOK_NORMAL,
- stream_unlink_cb, u);
- u->volume_control_implementation_initialized_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_IMPLEMENTATION_INITIALIZED],
- PA_HOOK_NORMAL, volume_control_implementation_initialized_cb, u);
- u->mute_control_implementation_initialized_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_IMPLEMENTATION_INITIALIZED],
- PA_HOOK_NORMAL, mute_control_implementation_initialized_cb, u);
- u->volume_control_set_initial_volume_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_SET_INITIAL_VOLUME], PA_HOOK_NORMAL,
- volume_control_set_initial_volume_cb, u);
- u->mute_control_set_initial_mute_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_SET_INITIAL_MUTE], PA_HOOK_NORMAL,
- mute_control_set_initial_mute_cb, u);
- u->volume_control_volume_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_VOLUME_CHANGED], PA_HOOK_NORMAL,
- volume_control_volume_changed_cb, u);
- u->mute_control_mute_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_MUTE_CHANGED], PA_HOOK_NORMAL,
- mute_control_mute_changed_cb, u);
- u->volume_control_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK],
- PA_HOOK_NORMAL, volume_control_unlink_cb, u);
- u->mute_control_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK],
- PA_HOOK_NORMAL, mute_control_unlink_cb, u);
- u->stream_rule_names = pa_dynarray_new(pa_xfree);
-
- f = pa_open_config_file(PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "audio-groups.conf", "audio-groups.conf", NULL, &fn);
- if (f) {
- pa_config_item config_items[] = {
- { "stream-rules", parse_streams, NULL, "General" },
- { NULL, parse_common, NULL, NULL },
- { NULL, NULL, NULL, NULL },
- };
-
- pa_config_parse(fn, f, config_items, NULL, u);
- pa_xfree(fn);
- fn = NULL;
- fclose(f);
- f = NULL;
- }
-
- PA_HASHMAP_FOREACH(group, u->groups, state)
- group_put(group);
-
- PA_DYNARRAY_FOREACH(name, u->stream_rule_names, idx) {
- struct stream_rule *rule;
-
- rule = pa_hashmap_get(u->stream_rules, name);
- if (rule)
- pa_dynarray_append(u->stream_rules_list, rule);
- else
- pa_log("Non-existent stream rule \"%s\" referenced, ignoring.", name);
- }
-
- pa_dynarray_free(u->stream_rule_names);
- u->stream_rule_names = NULL;
-
- pa_modargs_free(ma);
-
- return 0;
-
-fail:
- pa__done(module);
-
- if (ma)
- pa_modargs_free(ma);
-
- return -1;
-}
-
-void pa__done(pa_module *m) {
- struct userdata *u;
-
- pa_assert(m);
-
- u = (struct userdata *) m->userdata;
-
- if (!u)
- return;
-
- if (u->mute_control_unlink_slot)
- pa_hook_slot_free(u->mute_control_unlink_slot);
-
- if (u->volume_control_unlink_slot)
- pa_hook_slot_free(u->volume_control_unlink_slot);
-
- if (u->mute_control_mute_changed_slot)
- pa_hook_slot_free(u->mute_control_mute_changed_slot);
-
- if (u->volume_control_volume_changed_slot)
- pa_hook_slot_free(u->volume_control_volume_changed_slot);
-
- if (u->mute_control_set_initial_mute_slot)
- pa_hook_slot_free(u->mute_control_set_initial_mute_slot);
-
- if (u->volume_control_set_initial_volume_slot)
- pa_hook_slot_free(u->volume_control_set_initial_volume_slot);
-
- if (u->mute_control_implementation_initialized_slot)
- pa_hook_slot_free(u->mute_control_implementation_initialized_slot);
-
- if (u->volume_control_implementation_initialized_slot)
- pa_hook_slot_free(u->volume_control_implementation_initialized_slot);
-
- if (u->stream_unlink_slot)
- pa_hook_slot_free(u->stream_unlink_slot);
-
- if (u->stream_put_slot)
- pa_hook_slot_free(u->stream_put_slot);
-
- if (u->stream_mute_controls)
- pa_hashmap_free(u->stream_mute_controls);
-
- if (u->stream_volume_controls)
- pa_hashmap_free(u->stream_volume_controls);
-
- if (u->rules_by_stream)
- pa_hashmap_free(u->rules_by_stream);
-
- if (u->stream_rules_list)
- pa_dynarray_free(u->stream_rules_list);
-
- if (u->stream_rules)
- pa_hashmap_free(u->stream_rules);
-
- if (u->groups)
- pa_hashmap_free(u->groups);
-
- if (u->volume_api)
- pa_volume_api_unref(u->volume_api);
-
- pa_xfree(u);
-}
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "main-volume-context.h"
-
-#include <modules/volume-api/mute-control.h>
-#include <modules/volume-api/volume-control.h>
-
-#include <pulsecore/core-util.h>
-
-int pa_main_volume_context_new(pa_main_volume_policy *policy, const char *name, void *userdata, pa_main_volume_context **_r) {
- pa_main_volume_context *context;
- int r;
-
- pa_assert(policy);
- pa_assert(name);
- pa_assert(_r);
-
- context = pa_xnew0(struct pa_main_volume_context, 1);
- context->main_volume_policy = policy;
- context->index = pa_main_volume_policy_allocate_main_volume_context_index(policy);
-
- r = pa_main_volume_policy_register_name(policy, name, true, &context->name);
- if (r < 0)
- goto fail;
-
- context->description = pa_xstrdup(context->name);
- context->userdata = userdata;
-
- *_r = context;
- return 0;
-
-fail:
- if (context)
- pa_main_volume_context_free(context);
-
- return r;
-}
-
-void pa_main_volume_context_put(pa_main_volume_context *context) {
- pa_assert(context);
-
- pa_main_volume_policy_add_main_volume_context(context->main_volume_policy, context);
- context->linked = true;
-
- pa_log_debug("Created main volume context #%u.", context->index);
- pa_log_debug(" Name: %s", context->name);
- pa_log_debug(" Description: %s", context->description);
- pa_log_debug(" Main output volume control: %s",
- context->main_output_volume_control ? context->main_output_volume_control->name : "(unset)");
- pa_log_debug(" Main input volume control: %s",
- context->main_input_volume_control ? context->main_input_volume_control->name : "(unset)");
- pa_log_debug(" Main output mute control: %s",
- context->main_output_mute_control ? context->main_output_mute_control->name : "(unset)");
- pa_log_debug(" Main input mute control: %s",
- context->main_input_mute_control ? context->main_input_mute_control->name : "(unset)");
-
- pa_hook_fire(&context->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_PUT], context);
-}
-
-void pa_main_volume_context_unlink(pa_main_volume_context *context) {
- pa_assert(context);
-
- if (context->unlinked) {
- pa_log_debug("Unlinking main volume context %s (already unlinked, this is a no-op).", context->name);
- return;
- }
-
- context->unlinked = true;
-
- pa_log_debug("Unlinking main volume context %s.", context->name);
-
- if (context->linked)
- pa_main_volume_policy_remove_main_volume_context(context->main_volume_policy, context);
-
- pa_hook_fire(&context->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK], context);
-
- context->main_input_mute_control = NULL;
- context->main_output_mute_control = NULL;
- context->main_input_volume_control = NULL;
- context->main_output_volume_control = NULL;
-}
-
-void pa_main_volume_context_free(pa_main_volume_context *context) {
- pa_assert(context);
-
- /* unlink() expects name to be set. */
- if (!context->unlinked && context->name)
- pa_main_volume_context_unlink(context);
-
- pa_xfree(context->description);
-
- if (context->name)
- pa_main_volume_policy_unregister_name(context->main_volume_policy, context->name);
-
- pa_xfree(context);
-}
-
-void pa_main_volume_context_set_description(pa_main_volume_context *context, const char *description) {
- char *old_description;
-
- pa_assert(context);
- pa_assert(description);
-
- old_description = context->description;
-
- if (pa_streq(description, old_description))
- return;
-
- context->description = pa_xstrdup(description);
-
- if (!context->linked || context->unlinked) {
- pa_xfree(old_description);
- return;
- }
-
- pa_log_debug("Main volume context %s description changed from \"%s\" to \"%s\".", context->name, old_description,
- description);
- pa_xfree(old_description);
-
- pa_hook_fire(&context->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_DESCRIPTION_CHANGED],
- context);
-}
-
-void pa_main_volume_context_set_main_output_volume_control(pa_main_volume_context *context, pa_volume_control *control) {
- pa_volume_control *old_control;
-
- pa_assert(context);
-
- old_control = context->main_output_volume_control;
-
- if (control == old_control)
- return;
-
- context->main_output_volume_control = control;
-
- if (!context->linked || context->unlinked)
- return;
-
- pa_log_debug("Main volume context %s main output volume control changed from %s to %s.", context->name,
- old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-
- pa_hook_fire(&context->main_volume_policy->hooks
- [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED],
- context);
-}
-
-void pa_main_volume_context_set_main_input_volume_control(pa_main_volume_context *context, pa_volume_control *control) {
- pa_volume_control *old_control;
-
- pa_assert(context);
-
- old_control = context->main_input_volume_control;
-
- if (control == old_control)
- return;
-
- context->main_input_volume_control = control;
-
- if (!context->linked || context->unlinked)
- return;
-
- pa_log_debug("Main volume context %s main input volume control changed from %s to %s.", context->name,
- old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-
- pa_hook_fire(&context->main_volume_policy->hooks
- [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_VOLUME_CONTROL_CHANGED],
- context);
-}
-
-void pa_main_volume_context_set_main_output_mute_control(pa_main_volume_context *context, pa_mute_control *control) {
- pa_mute_control *old_control;
-
- pa_assert(context);
-
- old_control = context->main_output_mute_control;
-
- if (control == old_control)
- return;
-
- context->main_output_mute_control = control;
-
- if (!context->linked || context->unlinked)
- return;
-
- pa_log_debug("Main volume context %s main output mute control changed from %s to %s.", context->name,
- old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-
- pa_hook_fire(&context->main_volume_policy->hooks
- [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_MUTE_CONTROL_CHANGED],
- context);
-}
-
-void pa_main_volume_context_set_main_input_mute_control(pa_main_volume_context *context, pa_mute_control *control) {
- pa_mute_control *old_control;
-
- pa_assert(context);
-
- old_control = context->main_input_mute_control;
-
- if (control == old_control)
- return;
-
- context->main_input_mute_control = control;
-
- if (!context->linked || context->unlinked)
- return;
-
- pa_log_debug("Main volume context %s main input mute control changed from %s to %s.", context->name,
- old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-
- pa_hook_fire(&context->main_volume_policy->hooks
- [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_MUTE_CONTROL_CHANGED],
- context);
-}
+++ /dev/null
-#ifndef foomainvolumecontexthfoo
-#define foomainvolumecontexthfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <modules/main-volume-policy/main-volume-policy.h>
-
-typedef struct pa_main_volume_context pa_main_volume_context;
-
-struct pa_main_volume_context {
- pa_main_volume_policy *main_volume_policy;
- uint32_t index;
- const char *name;
- char *description;
- pa_volume_control *main_output_volume_control;
- pa_volume_control *main_input_volume_control;
- pa_mute_control *main_output_mute_control;
- pa_mute_control *main_input_mute_control;
-
- bool linked;
- bool unlinked;
-
- void *userdata;
-};
-
-int pa_main_volume_context_new(pa_main_volume_policy *policy, const char *name, void *userdata, pa_main_volume_context **_r);
-void pa_main_volume_context_put(pa_main_volume_context *context);
-void pa_main_volume_context_unlink(pa_main_volume_context *context);
-void pa_main_volume_context_free(pa_main_volume_context *context);
-
-void pa_main_volume_context_set_description(pa_main_volume_context *context, const char *description);
-void pa_main_volume_context_set_main_output_volume_control(pa_main_volume_context *context, pa_volume_control *control);
-void pa_main_volume_context_set_main_input_volume_control(pa_main_volume_context *context, pa_volume_control *control);
-void pa_main_volume_context_set_main_output_mute_control(pa_main_volume_context *context, pa_mute_control *control);
-void pa_main_volume_context_set_main_input_mute_control(pa_main_volume_context *context, pa_mute_control *control);
-
-#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "main-volume-policy.h"
-
-#include <modules/main-volume-policy/main-volume-context.h>
-
-#include <pulsecore/core-util.h>
-#include <pulsecore/namereg.h>
-#include <pulsecore/shared.h>
-
-static pa_main_volume_policy *main_volume_policy_new(pa_core *core);
-static void main_volume_policy_free(pa_main_volume_policy *policy);
-
-pa_main_volume_policy *pa_main_volume_policy_get(pa_core *core) {
- pa_main_volume_policy *policy;
-
- pa_assert(core);
-
- policy = pa_shared_get(core, "main-volume-policy");
-
- if (policy)
- pa_main_volume_policy_ref(policy);
- else {
- policy = main_volume_policy_new(core);
- pa_assert_se(pa_shared_set(core, "main-volume-policy", policy) >= 0);
- }
-
- return policy;
-}
-
-pa_main_volume_policy *pa_main_volume_policy_ref(pa_main_volume_policy *policy) {
- pa_assert(policy);
-
- policy->refcnt++;
-
- return policy;
-}
-
-void pa_main_volume_policy_unref(pa_main_volume_policy *policy) {
- pa_assert(policy);
- pa_assert(policy->refcnt > 0);
-
- policy->refcnt--;
-
- if (policy->refcnt == 0) {
- pa_assert_se(pa_shared_remove(policy->core, "main-volume-policy") >= 0);
- main_volume_policy_free(policy);
- }
-}
-
-static pa_hook_result_t volume_control_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- pa_main_volume_policy *policy = userdata;
- pa_volume_control *control = call_data;
- pa_main_volume_context *context;
- void *state;
-
- pa_assert(policy);
- pa_assert(control);
-
- PA_HASHMAP_FOREACH(context, policy->main_volume_contexts, state) {
- if (context->main_output_volume_control == control)
- pa_main_volume_context_set_main_output_volume_control(context, NULL);
-
- if (context->main_input_volume_control == control)
- pa_main_volume_context_set_main_input_volume_control(context, NULL);
- }
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t mute_control_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- pa_main_volume_policy *policy = userdata;
- pa_mute_control *control = call_data;
- pa_main_volume_context *context;
- void *state;
-
- pa_assert(policy);
- pa_assert(control);
-
- PA_HASHMAP_FOREACH(context, policy->main_volume_contexts, state) {
- if (context->main_output_mute_control == control)
- pa_main_volume_context_set_main_output_mute_control(context, NULL);
-
- if (context->main_input_mute_control == control)
- pa_main_volume_context_set_main_input_mute_control(context, NULL);
- }
-
- return PA_HOOK_OK;
-}
-
-static pa_main_volume_policy *main_volume_policy_new(pa_core *core) {
- pa_main_volume_policy *policy;
- unsigned i;
-
- pa_assert(core);
-
- policy = pa_xnew0(pa_main_volume_policy, 1);
- policy->core = core;
- policy->refcnt = 1;
- policy->volume_api = pa_volume_api_get(core);
- policy->names = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
- policy->main_volume_contexts = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-
- for (i = 0; i < PA_MAIN_VOLUME_POLICY_HOOK_MAX; i++)
- pa_hook_init(&policy->hooks[i], policy);
-
- policy->volume_control_unlink_slot = pa_hook_connect(&policy->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK],
- PA_HOOK_NORMAL, volume_control_unlink_cb, policy);
- policy->mute_control_unlink_slot = pa_hook_connect(&policy->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK],
- PA_HOOK_NORMAL, mute_control_unlink_cb, policy);
-
- pa_log_debug("Created a pa_main_volume_policy object.");
-
- return policy;
-}
-
-static void main_volume_policy_free(pa_main_volume_policy *policy) {
- unsigned i;
-
- pa_assert(policy);
- pa_assert(policy->refcnt == 0);
-
- pa_log_debug("Freeing the pa_main_volume_policy object.");
-
- if (policy->mute_control_unlink_slot)
- pa_hook_slot_free(policy->mute_control_unlink_slot);
-
- if (policy->volume_control_unlink_slot)
- pa_hook_slot_free(policy->volume_control_unlink_slot);
-
- for (i = 0; i < PA_MAIN_VOLUME_POLICY_HOOK_MAX; i++)
- pa_hook_done(&policy->hooks[i]);
-
- if (policy->main_volume_contexts) {
- pa_assert(pa_hashmap_isempty(policy->main_volume_contexts));
- pa_hashmap_free(policy->main_volume_contexts);
- }
-
- if (policy->names) {
- pa_assert(pa_hashmap_isempty(policy->names));
- pa_hashmap_free(policy->names);
- }
-
- if (policy->volume_api)
- pa_volume_api_unref(policy->volume_api);
-
- pa_xfree(policy);
-}
-
-int pa_main_volume_policy_register_name(pa_main_volume_policy *policy, const char *requested_name,
- bool fail_if_already_registered, const char **registered_name) {
- char *n;
-
- pa_assert(policy);
- pa_assert(requested_name);
- pa_assert(registered_name);
-
- if (!pa_namereg_is_valid_name(requested_name)) {
- pa_log("Invalid name: \"%s\"", requested_name);
- return -PA_ERR_INVALID;
- }
-
- n = pa_xstrdup(requested_name);
-
- if (pa_hashmap_put(policy->names, n, n) < 0) {
- unsigned i = 1;
-
- if (fail_if_already_registered) {
- pa_xfree(n);
- pa_log("Name %s already registered.", requested_name);
- return -PA_ERR_EXIST;
- }
-
- do {
- pa_xfree(n);
- i++;
- n = pa_sprintf_malloc("%s.%u", requested_name, i);
- } while (pa_hashmap_put(policy->names, n, n) < 0);
- }
-
- *registered_name = n;
-
- return 0;
-}
-
-void pa_main_volume_policy_unregister_name(pa_main_volume_policy *policy, const char *name) {
- pa_assert(policy);
- pa_assert(name);
-
- pa_assert_se(pa_hashmap_remove_and_free(policy->names, name) >= 0);
-}
-
-uint32_t pa_main_volume_policy_allocate_main_volume_context_index(pa_main_volume_policy *policy) {
- uint32_t idx;
-
- pa_assert(policy);
-
- idx = policy->next_main_volume_context_index++;
-
- return idx;
-}
-
-void pa_main_volume_policy_add_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context) {
- pa_assert(policy);
- pa_assert(context);
-
- pa_assert_se(pa_hashmap_put(policy->main_volume_contexts, (void *) context->name, context) >= 0);
-}
-
-int pa_main_volume_policy_remove_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context) {
- pa_assert(policy);
- pa_assert(context);
-
- if (!pa_hashmap_remove(policy->main_volume_contexts, context->name))
- return -1;
-
- if (context == policy->active_main_volume_context)
- pa_main_volume_policy_set_active_main_volume_context(policy, NULL);
-
- return 0;
-}
-
-void pa_main_volume_policy_set_active_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context) {
- pa_main_volume_context *old_context;
-
- pa_assert(policy);
-
- old_context = policy->active_main_volume_context;
-
- if (context == old_context)
- return;
-
- policy->active_main_volume_context = context;
-
- pa_log_debug("The active main volume context changed from %s to %s.", old_context ? old_context->name : "(unset)",
- context ? context->name : "(unset)");
-
- pa_hook_fire(&policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_ACTIVE_MAIN_VOLUME_CONTEXT_CHANGED], NULL);
-}
+++ /dev/null
-[General]
-output-volume-model = by-active-main-volume-context
-input-volume-model = by-active-main-volume-context
-output-mute-model = none
-input-mute-model = none
-
-[MainVolumeContext x-example-call-main-volume-context]
-description = Call main volume context
-main-output-volume-control = bind:AudioGroup:x-example-call-downlink-audio-group
-main-input-volume-control = bind:AudioGroup:x-example-call-uplink-audio-group
-main-output-mute-control = none
-main-input-mute-control = none
-
-[MainVolumeContext x-example-default-main-volume-context]
-description = Default main volume context
-main-output-volume-control = bind:AudioGroup:x-example-default-output-audio-group
-main-input-volume-control = bind:AudioGroup:x-example-default-input-audio-group
-main-output-mute-control = none
-main-input-mute-control = none
+++ /dev/null
-#ifndef foomainvolumepolicyhfoo
-#define foomainvolumepolicyhfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <modules/volume-api/volume-api.h>
-
-#include <pulsecore/core.h>
-
-typedef struct pa_main_volume_policy pa_main_volume_policy;
-
-/* Avoid circular dependencies... */
-typedef struct pa_main_volume_context pa_main_volume_context;
-
-enum {
- PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_PUT,
- PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK,
- PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_DESCRIPTION_CHANGED,
- PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED,
- PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_VOLUME_CONTROL_CHANGED,
- PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_MUTE_CONTROL_CHANGED,
- PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_MUTE_CONTROL_CHANGED,
- PA_MAIN_VOLUME_POLICY_HOOK_ACTIVE_MAIN_VOLUME_CONTEXT_CHANGED,
- PA_MAIN_VOLUME_POLICY_HOOK_MAX,
-};
-
-struct pa_main_volume_policy {
- pa_core *core;
- unsigned refcnt;
- pa_volume_api *volume_api;
- pa_hashmap *names; /* object name -> object name (hashmap-as-a-set) */
- pa_hashmap *main_volume_contexts; /* name -> pa_main_volume_context */
- pa_main_volume_context *active_main_volume_context;
-
- uint32_t next_main_volume_context_index;
- pa_hook hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAX];
-
- pa_hook_slot *volume_control_unlink_slot;
- pa_hook_slot *mute_control_unlink_slot;
-};
-
-pa_main_volume_policy *pa_main_volume_policy_get(pa_core *core);
-pa_main_volume_policy *pa_main_volume_policy_ref(pa_main_volume_policy *policy);
-void pa_main_volume_policy_unref(pa_main_volume_policy *policy);
-
-int pa_main_volume_policy_register_name(pa_main_volume_policy *policy, const char *requested_name,
- bool fail_if_already_registered, const char **registered_name);
-void pa_main_volume_policy_unregister_name(pa_main_volume_policy *policy, const char *name);
-
-uint32_t pa_main_volume_policy_allocate_main_volume_context_index(pa_main_volume_policy *policy);
-void pa_main_volume_policy_add_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context);
-int pa_main_volume_policy_remove_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context);
-void pa_main_volume_policy_set_active_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context);
-
-#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "module-main-volume-policy-symdef.h"
-
-#include <modules/main-volume-policy/main-volume-context.h>
-
-#include <modules/volume-api/audio-group.h>
-#include <modules/volume-api/volume-api.h>
-
-#include <pulse/direction.h>
-
-#include <pulsecore/conf-parser.h>
-#include <pulsecore/core-util.h>
-#include <pulsecore/i18n.h>
-
-#define BIND_PREFIX "bind:"
-#define BIND_AUDIO_GROUP_PREFIX BIND_PREFIX "AudioGroup:"
-
-PA_MODULE_AUTHOR("Tanu Kaskinen");
-PA_MODULE_DESCRIPTION(_("Main volume and mute policy"));
-PA_MODULE_VERSION(PACKAGE_VERSION);
-PA_MODULE_LOAD_ONCE(true);
-
-enum control_type {
- CONTROL_TYPE_VOLUME,
- CONTROL_TYPE_MUTE,
-};
-
-enum model {
- MODEL_NONE,
- MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT,
-};
-
-struct userdata {
- pa_volume_api *volume_api;
- pa_main_volume_policy *main_volume_policy;
- enum model output_volume_model;
- enum model input_volume_model;
- enum model output_mute_model;
- enum model input_mute_model;
- pa_hashmap *contexts; /* name -> struct context */
-
- pa_hook_slot *active_main_volume_context_changed_slot;
- pa_hook_slot *main_volume_context_main_output_volume_control_changed_slot;
- pa_hook_slot *main_volume_context_main_input_volume_control_changed_slot;
- pa_hook_slot *main_volume_context_main_output_mute_control_changed_slot;
- pa_hook_slot *main_volume_context_main_input_mute_control_changed_slot;
- pa_hook_slot *audio_group_put_slot;
- pa_hook_slot *audio_group_unlink_slot;
- pa_hook_slot *audio_group_volume_control_changed_slot;
- pa_hook_slot *audio_group_mute_control_changed_slot;
-};
-
-struct control_info {
- /* As appropriate for this control, points to one of
- * - pa_main_volume_context.main_output_volume_control
- * - pa_main_volume_context.main_input_volume_control
- * - pa_main_volume_context.main_output_mute_control
- * - pa_main_volume_context.main_input_mute_control */
- void **control;
-
- /* As appropriate for this control, points to one of
- * - userdata.output_volume_model
- * - userdata.input_volume_model
- * - userdata.output_mute_model
- * - userdata.input_mute_model */
- enum model *model;
-
- /* Name of the audio group to which the context volume or mute control is
- * bound. If the context control is not bound to anything, this is NULL. */
- char *binding_target_name;
-
- /* Points to the audio group to which the context volume or mute control is
- * bound. If the context control is not bound to anything, or it's bound
- * but the target doesn't currently exist, this is NULL. */
- pa_audio_group *binding_target;
-
- /* As appropriate for this control, points to one of
- * - pa_main_volume_context_set_main_output_volume_control()
- * - pa_main_volume_context_set_main_input_volume_control()
- * - pa_main_volume_context_set_main_output_mute_control()
- * - pa_main_volume_context_set_main_input_mute_control() */
- void (*set_control)(pa_main_volume_context *context, void *control);
-
- /* As appropriate for this control, points to one of
- * - pa_volume_api_set_main_output_volume_control()
- * - pa_volume_api_set_main_input_volume_control()
- * - pa_volume_api_set_main_output_mute_control()
- * - pa_volume_api_set_main_input_mute_control() */
- void (*set_volume_api_control)(pa_volume_api *api, void *control);
-};
-
-struct context {
- struct userdata *userdata;
- pa_main_volume_context *main_volume_context;
- struct control_info output_volume_info;
- struct control_info input_volume_info;
- struct control_info output_mute_info;
- struct control_info input_mute_info;
-
- bool unlinked;
-};
-
-static void context_free(struct context *context);
-
-static const char *model_to_string(enum model model) {
- switch (model) {
- case MODEL_NONE:
- return "none";
-
- case MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT:
- return "by-active-main-volume-context";
- }
-
- pa_assert_not_reached();
-}
-
-static int model_from_string(const char *str, enum model *model) {
- pa_assert(str);
- pa_assert(model);
-
- if (pa_streq(str, "none"))
- *model = MODEL_NONE;
- else if (pa_streq(str, "by-active-main-volume-context"))
- *model = MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT;
- else
- return -PA_ERR_INVALID;
-
- return 0;
-}
-
-static int context_new(struct userdata *u, const char *name, struct context **_r) {
- struct context *context = NULL;
- int r;
-
- pa_assert(u);
- pa_assert(name);
- pa_assert(_r);
-
- context = pa_xnew0(struct context, 1);
- context->userdata = u;
-
- r = pa_main_volume_context_new(u->main_volume_policy, name, u, &context->main_volume_context);
- if (r < 0)
- goto fail;
-
- context->output_volume_info.control = (void **) &context->main_volume_context->main_output_volume_control;
- context->input_volume_info.control = (void **) &context->main_volume_context->main_input_volume_control;
- context->output_mute_info.control = (void **) &context->main_volume_context->main_output_mute_control;
- context->input_mute_info.control = (void **) &context->main_volume_context->main_input_mute_control;
-
- context->output_volume_info.model = &u->output_volume_model;
- context->input_volume_info.model = &u->input_volume_model;
- context->output_mute_info.model = &u->output_mute_model;
- context->input_mute_info.model = &u->input_mute_model;
-
- context->output_volume_info.set_control = (void *) pa_main_volume_context_set_main_output_volume_control;
- context->input_volume_info.set_control = (void *) pa_main_volume_context_set_main_input_volume_control;
- context->output_mute_info.set_control = (void *) pa_main_volume_context_set_main_output_mute_control;
- context->input_mute_info.set_control = (void *) pa_main_volume_context_set_main_input_mute_control;
-
- context->output_volume_info.set_volume_api_control = (void *) pa_volume_api_set_main_output_volume_control;
- context->input_volume_info.set_volume_api_control = (void *) pa_volume_api_set_main_input_volume_control;
- context->output_mute_info.set_volume_api_control = (void *) pa_volume_api_set_main_output_mute_control;
- context->input_mute_info.set_volume_api_control = (void *) pa_volume_api_set_main_input_mute_control;
-
- *_r = context;
- return 0;
-
-fail:
- if (context)
- context_free(context);
-
- return r;
-}
-
-static void context_put(struct context *context) {
- pa_assert(context);
-
- pa_main_volume_context_put(context->main_volume_context);
-}
-
-static void context_unlink(struct context *context) {
- pa_assert(context);
-
- if (context->unlinked)
- return;
-
- context->unlinked = true;
-
- if (context->main_volume_context)
- pa_main_volume_context_unlink(context->main_volume_context);
-}
-
-static void context_free(struct context *context) {
- pa_assert(context);
-
- if (!context->unlinked)
- context_unlink(context);
-
- if (context->main_volume_context)
- pa_main_volume_context_free(context->main_volume_context);
-
- pa_xfree(context);
-}
-
-static struct control_info *context_get_control_info(struct context *context, enum control_type type,
- pa_direction_t direction) {
- pa_assert(context);
-
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- switch (direction) {
- case PA_DIRECTION_OUTPUT:
- return &context->output_volume_info;
-
- case PA_DIRECTION_INPUT:
- return &context->input_volume_info;
- }
- break;
-
- case CONTROL_TYPE_MUTE:
- switch (direction) {
- case PA_DIRECTION_OUTPUT:
- return &context->output_mute_info;
-
- case PA_DIRECTION_INPUT:
- return &context->input_mute_info;
- }
- break;
- }
-
- pa_assert_not_reached();
-}
-
-static void context_set_binding_target(struct context *context, enum control_type type, pa_direction_t direction,
- pa_audio_group *group) {
- struct control_info *info;
- void *control = NULL;
-
- pa_assert(context);
-
- info = context_get_control_info(context, type, direction);
- info->binding_target = group;
-
- if (group) {
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- control = group->volume_control;
- break;
-
- case CONTROL_TYPE_MUTE:
- control = group->mute_control;
- break;
- }
- }
-
- info->set_control(context->main_volume_context, control);
-}
-
-static void context_set_binding_target_name(struct context *context, enum control_type type, pa_direction_t direction,
- const char *name) {
- struct control_info *info;
- pa_audio_group *group = NULL;
-
- pa_assert(context);
-
- info = context_get_control_info(context, type, direction);
-
- if (pa_safe_streq(name, info->binding_target_name))
- return;
-
- pa_xfree(info->binding_target_name);
- info->binding_target_name = pa_xstrdup(name);
-
- if (name)
- group = pa_hashmap_get(context->userdata->volume_api->audio_groups, name);
-
- context_set_binding_target(context, type, direction, group);
-}
-
-static pa_hook_result_t active_main_volume_context_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_main_volume_context *context;
-
- pa_assert(u);
-
- context = u->main_volume_policy->active_main_volume_context;
-
- if (u->output_volume_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
- if (context)
- pa_volume_api_set_main_output_volume_control(u->volume_api, context->main_output_volume_control);
- else
- pa_volume_api_set_main_output_volume_control(u->volume_api, NULL);
- }
-
- if (u->input_volume_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
- if (context)
- pa_volume_api_set_main_input_volume_control(u->volume_api, context->main_input_volume_control);
- else
- pa_volume_api_set_main_input_volume_control(u->volume_api, NULL);
- }
-
- if (u->output_mute_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
- if (context)
- pa_volume_api_set_main_output_mute_control(u->volume_api, context->main_output_mute_control);
- else
- pa_volume_api_set_main_output_mute_control(u->volume_api, NULL);
- }
-
- if (u->input_mute_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
- if (context)
- pa_volume_api_set_main_input_mute_control(u->volume_api, context->main_input_mute_control);
- else
- pa_volume_api_set_main_input_mute_control(u->volume_api, NULL);
- }
-
- return PA_HOOK_OK;
-}
-
-static void handle_context_control_change(struct context *context, enum control_type type, pa_direction_t direction) {
- struct control_info *info;
-
- pa_assert(context);
-
- info = context_get_control_info(context, type, direction);
-
- if (*info->model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT
- && context->userdata->main_volume_policy->active_main_volume_context == context->main_volume_context)
- info->set_volume_api_control(context->userdata->volume_api, *info->control);
-}
-
-static pa_hook_result_t main_volume_context_main_output_volume_control_changed_cb(void *hook_data, void *call_data,
- void *userdata) {
- pa_main_volume_context *context = call_data;
-
- pa_assert(context);
-
- handle_context_control_change(context->userdata, CONTROL_TYPE_VOLUME, PA_DIRECTION_OUTPUT);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t main_volume_context_main_input_volume_control_changed_cb(void *hook_data, void *call_data,
- void *userdata) {
- pa_main_volume_context *context = call_data;
-
- pa_assert(context);
-
- handle_context_control_change(context->userdata, CONTROL_TYPE_VOLUME, PA_DIRECTION_INPUT);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t main_volume_context_main_output_mute_control_changed_cb(void *hook_data, void *call_data,
- void *userdata) {
- pa_main_volume_context *context = call_data;
-
- pa_assert(context);
-
- handle_context_control_change(context->userdata, CONTROL_TYPE_MUTE, PA_DIRECTION_OUTPUT);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t main_volume_context_main_input_mute_control_changed_cb(void *hook_data, void *call_data,
- void *userdata) {
- pa_main_volume_context *context = call_data;
-
- pa_assert(context);
-
- handle_context_control_change(context->userdata, CONTROL_TYPE_MUTE, PA_DIRECTION_INPUT);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t audio_group_put_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_audio_group *group = call_data;
- struct context *context;
- void *state;
-
- pa_assert(u);
- pa_assert(group);
-
- PA_HASHMAP_FOREACH(context, u->contexts, state) {
- if (context->output_volume_info.binding_target_name
- && pa_streq(context->output_volume_info.binding_target_name, group->name))
- context_set_binding_target(context, CONTROL_TYPE_VOLUME, PA_DIRECTION_OUTPUT, group);
-
- if (context->input_volume_info.binding_target_name
- && pa_streq(context->input_volume_info.binding_target_name, group->name))
- context_set_binding_target(context, CONTROL_TYPE_VOLUME, PA_DIRECTION_INPUT, group);
-
- if (context->output_mute_info.binding_target_name
- && pa_streq(context->output_mute_info.binding_target_name, group->name))
- context_set_binding_target(context, CONTROL_TYPE_MUTE, PA_DIRECTION_OUTPUT, group);
-
- if (context->input_mute_info.binding_target_name
- && pa_streq(context->input_mute_info.binding_target_name, group->name))
- context_set_binding_target(context, CONTROL_TYPE_MUTE, PA_DIRECTION_INPUT, group);
- }
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t audio_group_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_audio_group *group = call_data;
- struct context *context;
- void *state;
-
- pa_assert(u);
- pa_assert(group);
-
- PA_HASHMAP_FOREACH(context, u->contexts, state) {
- if (context->output_volume_info.binding_target == group)
- context_set_binding_target(context, CONTROL_TYPE_VOLUME, PA_DIRECTION_OUTPUT, NULL);
-
- if (context->input_volume_info.binding_target == group)
- context_set_binding_target(context, CONTROL_TYPE_VOLUME, PA_DIRECTION_INPUT, NULL);
-
- if (context->output_mute_info.binding_target == group)
- context_set_binding_target(context, CONTROL_TYPE_MUTE, PA_DIRECTION_OUTPUT, NULL);
-
- if (context->input_mute_info.binding_target == group)
- context_set_binding_target(context, CONTROL_TYPE_MUTE, PA_DIRECTION_INPUT, NULL);
- }
-
- return PA_HOOK_OK;
-}
-
-static void handle_audio_group_control_change(struct userdata *u, pa_audio_group *group, enum control_type type) {
- struct context *context;
- void *state;
-
- pa_assert(u);
- pa_assert(group);
-
- PA_HASHMAP_FOREACH(context, u->contexts, state) {
- switch (type) {
- case CONTROL_TYPE_VOLUME:
- if (context->output_volume_info.binding_target == group)
- pa_main_volume_context_set_main_output_volume_control(context->main_volume_context, group->volume_control);
-
- if (context->input_volume_info.binding_target == group)
- pa_main_volume_context_set_main_input_volume_control(context->main_volume_context, group->volume_control);
- break;
-
- case CONTROL_TYPE_MUTE:
- if (context->output_mute_info.binding_target == group)
- pa_main_volume_context_set_main_output_mute_control(context->main_volume_context, group->mute_control);
-
- if (context->input_mute_info.binding_target == group)
- pa_main_volume_context_set_main_input_mute_control(context->main_volume_context, group->mute_control);
- break;
- }
- }
-}
-
-static pa_hook_result_t audio_group_volume_control_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_audio_group *group = call_data;
-
- pa_assert(u);
- pa_assert(group);
-
- handle_audio_group_control_change(u, group, CONTROL_TYPE_VOLUME);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t audio_group_mute_control_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_audio_group *group = call_data;
-
- pa_assert(u);
- pa_assert(group);
-
- handle_audio_group_control_change(u, group, CONTROL_TYPE_MUTE);
-
- return PA_HOOK_OK;
-}
-
-static int parse_model(pa_config_parser_state *state) {
- int r;
-
- pa_assert(state);
-
- r = model_from_string(state->rvalue, state->data);
- if (r < 0)
- pa_log("[%s:%u] Failed to parse model: %s", state->filename, state->lineno, state->rvalue);
-
- return r;
-}
-
-static int get_context(struct userdata *u, const char *section, struct context **_r) {
- const char *name;
- struct context *context;
-
- pa_assert(u);
-
- if (!section)
- return -PA_ERR_INVALID;
-
- if (!pa_startswith(section, "MainVolumeContext "))
- return -PA_ERR_INVALID;
-
- name = section + 18;
-
- context = pa_hashmap_get(u->contexts, name);
- if (!context) {
- int r;
-
- r = context_new(u, name, &context);
- if (r < 0)
- return r;
-
- pa_hashmap_put(u->contexts, (void *) context->main_volume_context->name, context);
- }
-
- *_r = context;
- return 0;
-}
-
-static int parse_description(pa_config_parser_state *state) {
- struct userdata *u;
- int r;
- struct context *context;
-
- pa_assert(state);
-
- u = state->userdata;
-
- r = get_context(u, state->section, &context);
- if (r < 0) {
- pa_log("[%s:%u] Couldn't get main volume context for section \"%s\".", state->filename, state->lineno,
- pa_strnull(state->section));
- return -PA_ERR_INVALID;
- }
-
- pa_main_volume_context_set_description(context->main_volume_context, state->rvalue);
-
- return 0;
-}
-
-static int parse_control(pa_config_parser_state *state, enum control_type type, pa_direction_t direction) {
- struct userdata *u;
- int r;
- struct context *context;
-
- pa_assert(state);
-
- u = state->userdata;
-
- r = get_context(u, state->section, &context);
- if (r < 0) {
- pa_log("[%s:%u] Couldn't get main volume context for section \"%s\".", state->filename, state->lineno,
- pa_strnull(state->section));
- return -PA_ERR_INVALID;
- }
-
- if (pa_streq(state->rvalue, "none"))
- context_set_binding_target_name(context, type, direction, NULL);
- else if (pa_startswith(state->rvalue, BIND_PREFIX)) {
- if (pa_startswith(state->rvalue, BIND_AUDIO_GROUP_PREFIX))
- context_set_binding_target_name(context, type, direction, state->rvalue + strlen(BIND_AUDIO_GROUP_PREFIX));
- else {
- pa_log("[%s:%u] Failed to parse binding target \"%s\".", state->filename, state->lineno, state->rvalue + strlen(BIND_PREFIX));
- return -PA_ERR_INVALID;
- }
- } else {
- pa_log("[%s:%u] Failed to parse value \"%s\".", state->filename, state->lineno, state->rvalue);
- return -PA_ERR_INVALID;
- }
-
- return 0;
-}
-
-static int parse_main_output_volume_control(pa_config_parser_state *state) {
- pa_assert(state);
-
- return parse_control(state, CONTROL_TYPE_VOLUME, PA_DIRECTION_OUTPUT);
-}
-
-static int parse_main_input_volume_control(pa_config_parser_state *state) {
- pa_assert(state);
-
- return parse_control(state, CONTROL_TYPE_VOLUME, PA_DIRECTION_INPUT);
-}
-
-static int parse_main_output_mute_control(pa_config_parser_state *state) {
- pa_assert(state);
-
- return parse_control(state, CONTROL_TYPE_MUTE, PA_DIRECTION_OUTPUT);
-}
-
-static int parse_main_input_mute_control(pa_config_parser_state *state) {
- pa_assert(state);
-
- return parse_control(state, CONTROL_TYPE_MUTE, PA_DIRECTION_INPUT);
-}
-
-int pa__init(pa_module *module) {
- struct userdata *u;
- FILE *f;
- char *fn = NULL;
- struct context *context;
- void *state;
-
- pa_assert(module);
-
- u = module->userdata = pa_xnew0(struct userdata, 1);
- u->volume_api = pa_volume_api_get(module->core);
- u->main_volume_policy = pa_main_volume_policy_get(module->core);
- u->output_volume_model = MODEL_NONE;
- u->input_volume_model = MODEL_NONE;
- u->output_mute_model = MODEL_NONE;
- u->input_mute_model = MODEL_NONE;
- u->contexts = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
- (pa_free_cb_t) context_free);
- u->active_main_volume_context_changed_slot =
- pa_hook_connect(&u->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_ACTIVE_MAIN_VOLUME_CONTEXT_CHANGED],
- PA_HOOK_NORMAL, active_main_volume_context_changed_cb, u);
- u->main_volume_context_main_output_volume_control_changed_slot =
- pa_hook_connect(&u->main_volume_policy->hooks
- [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED],
- PA_HOOK_NORMAL, main_volume_context_main_output_volume_control_changed_cb, u);
- u->main_volume_context_main_input_volume_control_changed_slot =
- pa_hook_connect(&u->main_volume_policy->hooks
- [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_VOLUME_CONTROL_CHANGED],
- PA_HOOK_NORMAL, main_volume_context_main_input_volume_control_changed_cb, u);
- u->main_volume_context_main_output_mute_control_changed_slot =
- pa_hook_connect(&u->main_volume_policy->hooks
- [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_MUTE_CONTROL_CHANGED],
- PA_HOOK_NORMAL, main_volume_context_main_output_mute_control_changed_cb, u);
- u->main_volume_context_main_input_mute_control_changed_slot =
- pa_hook_connect(&u->main_volume_policy->hooks
- [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_MUTE_CONTROL_CHANGED],
- PA_HOOK_NORMAL, main_volume_context_main_input_mute_control_changed_cb, u);
- u->audio_group_put_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_PUT], PA_HOOK_NORMAL,
- audio_group_put_cb, u);
- u->audio_group_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK], PA_HOOK_NORMAL,
- audio_group_unlink_cb, u);
- u->audio_group_volume_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_VOLUME_CONTROL_CHANGED], PA_HOOK_NORMAL,
- audio_group_volume_control_changed_cb, u);
- u->audio_group_mute_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_MUTE_CONTROL_CHANGED], PA_HOOK_NORMAL,
- audio_group_mute_control_changed_cb, u);
-
- f = pa_open_config_file(PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "main-volume-policy.conf", "main-volume-policy.conf", NULL, &fn);
- if (f) {
- pa_config_item config_items[] = {
- { "output-volume-model", parse_model, &u->output_volume_model, "General" },
- { "input-volume-model", parse_model, &u->input_volume_model, "General" },
- { "output-mute-model", parse_model, &u->output_mute_model, "General" },
- { "input-mute-model", parse_model, &u->input_mute_model, "General" },
- { "description", parse_description, NULL, NULL },
- { "main-output-volume-control", parse_main_output_volume_control, NULL, NULL },
- { "main-input-volume-control", parse_main_input_volume_control, NULL, NULL },
- { "main-output-mute-control", parse_main_output_mute_control, NULL, NULL },
- { "main-input-mute-control", parse_main_input_mute_control, NULL, NULL },
- { NULL },
- };
-
- pa_config_parse(fn, f, config_items, NULL, u);
- pa_xfree(fn);
- fn = NULL;
- fclose(f);
- f = NULL;
- }
-
- PA_HASHMAP_FOREACH(context, u->contexts, state)
- context_put(context);
-
- pa_log_debug("Output volume model: %s", model_to_string(u->output_volume_model));
- pa_log_debug("Input volume model: %s", model_to_string(u->input_volume_model));
- pa_log_debug("Output mute model: %s", model_to_string(u->output_mute_model));
- pa_log_debug("Input mute model: %s", model_to_string(u->input_mute_model));
-
- return 0;
-}
-
-void pa__done(pa_module *module) {
- struct userdata *u;
-
- pa_assert(module);
-
- u = module->userdata;
- if (!u)
- return;
-
- if (u->audio_group_mute_control_changed_slot)
- pa_hook_slot_free(u->audio_group_mute_control_changed_slot);
-
- if (u->audio_group_volume_control_changed_slot)
- pa_hook_slot_free(u->audio_group_volume_control_changed_slot);
-
- if (u->audio_group_unlink_slot)
- pa_hook_slot_free(u->audio_group_unlink_slot);
-
- if (u->audio_group_put_slot)
- pa_hook_slot_free(u->audio_group_put_slot);
-
- if (u->main_volume_context_main_input_mute_control_changed_slot)
- pa_hook_slot_free(u->main_volume_context_main_input_mute_control_changed_slot);
-
- if (u->main_volume_context_main_output_mute_control_changed_slot)
- pa_hook_slot_free(u->main_volume_context_main_output_mute_control_changed_slot);
-
- if (u->main_volume_context_main_input_volume_control_changed_slot)
- pa_hook_slot_free(u->main_volume_context_main_input_volume_control_changed_slot);
-
- if (u->main_volume_context_main_output_volume_control_changed_slot)
- pa_hook_slot_free(u->main_volume_context_main_output_volume_control_changed_slot);
-
- if (u->active_main_volume_context_changed_slot)
- pa_hook_slot_free(u->active_main_volume_context_changed_slot);
-
- if (u->contexts)
- pa_hashmap_free(u->contexts);
-
- if (u->main_volume_policy)
- pa_main_volume_policy_unref(u->main_volume_policy);
-
- if (u->volume_api)
- pa_volume_api_unref(u->volume_api);
-
- pa_xfree(u);
-}
+++ /dev/null
-==== v1 ====
-
-client->server
-CONNECT
- uint32 version
-reply
- uint32 version
-
-
-client->server, server->client
-DISCONNECT
- (no arguments)
-(no reply)
-
-
-client->server
-SUBSCRIBE
- uint32 mask
-reply
- (no arguments)
-
-
-server->client
-SUBSCRIBE_EVENT
- uint32 event_type
- uint32 index
-(no reply)
-
-
-client->server
-GET_SERVER_INFO
- (no arguments)
-reply
- uint32 main_output_volume_control
- uint32 main_input_volume_control
- uint32 main_output_mute_control
- uint32 main_input_mute_control
-
-
-client->server
-GET_VOLUME_CONTROL_INFO
- uint32 index
- string name
-reply
- uint32 index
- string name
- string description
- proplist proplist
- volume volume
- channel_map channel_map
- uint64 balance (repeated channel_map.channels times)
- boolean convertible_to_dB
-
-
-client->server
-GET_VOLUME_CONTROL_INFO_LIST
- (no arguments)
-reply
- (the same arguments as with GET_VOLUME_CONTROL_INFO, repeated for each
- volume control in the system)
-
-
-client->server
-SET_VOLUME_CONTROL_VOLUME
- uint32 index
- string name
- volume volume
- channel_map channel_map
- uint64 balance (repeated channel_map.channels times)
-reply
- (no arguments)
-
-
-client->server
-GET_MUTE_CONTROL_INFO
- uint32 index
- string name
-reply
- uint32 index
- string name
- string description
- proplist proplist
- boolean mute
-
-
-client->server
-GET_MUTE_CONTROL_INFO_LIST
- (no arguments)
-reply
- (the same arguments as with GET_MUTE_CONTROL_INFO, repeated for each mute
- control in the system)
-
-
-client->server
-SET_MUTE_CONTROL_MUTE
- uint32 index
- string name
- boolean mute
-reply
- (no arguments)
-
-
-client->server
-GET_DEVICE_INFO
- uint32 index
- string name
-reply
- uint32 index
- string name
- string description
- uint8 direction
- uint32 n_device_types
- string device_type (repeated n_device_types times)
- proplist proplist
- uint32 volume_control
- uint32 mute_control
-
-
-client->server
-GET_DEVICE_INFO_LIST
- (no arguments)
-reply
- (the same arguments as with GET_DEVICE_INFO, repeated for each device in
- the system)
-
-
-client->server
-GET_STREAM_INFO
- uint32 index
- string name
-reply
- uint32 index
- string name
- string description
- uint8 direction
- proplist proplist
- uint32 volume_control
- uint32 mute_control
-
-
-client->server
-GET_STREAM_INFO_LIST
- (no arguments)
-reply
- (the same arguments as with GET_STREAM_INFO, repeated for each stream in
- the system)
-
-
-client->server
-GET_AUDIO_GROUP_INFO
- uint32 index
- string name
-reply
- uint32 index
- string name
- string description
- proplist proplist
- uint32 volume_control
- uint32 mute_control
-
-
-client->server
-GET_AUDIO_GROUP_INFO_LIST
- (no arguments)
-reply
- (the same arguments as with GET_AUDIO_GROUP_INFO, repeated for each audio
- group in the system)
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "audio-group.h"
-
-#include <modules/volume-api/sstream.h>
-
-#include <pulsecore/core-util.h>
-
-int pa_audio_group_new(pa_volume_api *api, const char *name, pa_audio_group **_r) {
- pa_audio_group *group = NULL;
- int r;
-
- pa_assert(api);
- pa_assert(name);
- pa_assert(_r);
-
- group = pa_xnew0(pa_audio_group, 1);
- group->volume_api = api;
- group->index = pa_volume_api_allocate_audio_group_index(api);
-
- r = pa_volume_api_register_name(api, name, true, &group->name);
- if (r < 0)
- goto fail;
-
- group->description = pa_xstrdup(group->name);
- group->proplist = pa_proplist_new();
- group->volume_streams = pa_hashmap_new(NULL, NULL);
- group->mute_streams = pa_hashmap_new(NULL, NULL);
-
- *_r = group;
- return 0;
-
-fail:
- if (group)
- pa_audio_group_free(group);
-
- return r;
-}
-
-void pa_audio_group_put(pa_audio_group *group) {
- const char *prop_key;
- void *state = NULL;
-
- pa_assert(group);
-
- pa_volume_api_add_audio_group(group->volume_api, group);
- group->linked = true;
-
- pa_log_debug("Created audio group #%u.", group->index);
- pa_log_debug(" Name: %s", group->name);
- pa_log_debug(" Description: %s", group->description);
- pa_log_debug(" Volume control: %s", group->volume_control ? group->volume_control->name : "(unset)");
- pa_log_debug(" Mute control: %s", group->mute_control ? group->mute_control->name : "(unset)");
- pa_log_debug(" Properties:");
-
- while ((prop_key = pa_proplist_iterate(group->proplist, &state)))
- pa_log_debug(" %s = %s", prop_key, pa_strnull(pa_proplist_gets(group->proplist, prop_key)));
-
- pa_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_PUT], group);
-}
-
-void pa_audio_group_unlink(pa_audio_group *group) {
- pas_stream *stream;
-
- pa_assert(group);
-
- if (group->unlinked) {
- pa_log_debug("Unlinking audio group %s (already unlinked, this is a no-op).", group->name);
- return;
- }
-
- group->unlinked = true;
-
- pa_log_debug("Unlinking audio group %s.", group->name);
-
- if (group->linked)
- pa_volume_api_remove_audio_group(group->volume_api, group);
-
- pa_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK], group);
-
- while ((stream = pa_hashmap_first(group->mute_streams)))
- pas_stream_set_audio_group_for_mute(stream, NULL);
-
- while ((stream = pa_hashmap_first(group->volume_streams)))
- pas_stream_set_audio_group_for_volume(stream, NULL);
-
- pa_audio_group_set_mute_control(group, NULL);
- pa_audio_group_set_volume_control(group, NULL);
-}
-
-void pa_audio_group_free(pa_audio_group *group) {
- pa_assert(group);
-
- /* unlink() expects name to be set. */
- if (!group->unlinked && group->name)
- pa_audio_group_unlink(group);
-
- if (group->mute_streams)
- pa_hashmap_free(group->mute_streams);
-
- if (group->volume_streams)
- pa_hashmap_free(group->volume_streams);
-
- if (group->proplist)
- pa_proplist_free(group->proplist);
-
- pa_xfree(group->description);
-
- if (group->name)
- pa_volume_api_unregister_name(group->volume_api, group->name);
-
- pa_xfree(group);
-}
-
-void pa_audio_group_set_description(pa_audio_group *group, const char *description) {
- char *old_description;
-
- pa_assert(group);
- pa_assert(description);
-
- old_description = group->description;
-
- if (pa_streq(description, old_description))
- return;
-
- group->description = pa_xstrdup(description);
-
- if (!group->linked || group->unlinked) {
- pa_xfree(old_description);
- return;
- }
-
- pa_log_debug("The description of audio group %s changed from \"%s\" to \"%s\".", group->name, old_description,
- description);
- pa_xfree(old_description);
-
- pa_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_DESCRIPTION_CHANGED], group);
-
-}
-
-void pa_audio_group_set_volume_control(pa_audio_group *group, pa_volume_control *control) {
- pa_volume_control *old_control;
-
- pa_assert(group);
-
- old_control = group->volume_control;
-
- if (control == old_control)
- return;
-
- group->volume_control = control;
-
- if (!group->linked || group->unlinked)
- return;
-
- pa_log_debug("The volume control of audio group %s changed from %s to %s.", group->name,
- old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-
- pa_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_VOLUME_CONTROL_CHANGED], group);
-}
-
-void pa_audio_group_set_mute_control(pa_audio_group *group, pa_mute_control *control) {
- pa_mute_control *old_control;
-
- pa_assert(group);
-
- old_control = group->mute_control;
-
- if (control == old_control)
- return;
-
- group->mute_control = control;
-
- if (!group->linked || group->unlinked)
- return;
-
- pa_log_debug("The mute control of audio group %s changed from %s to %s.", group->name,
- old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-
- pa_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_MUTE_CONTROL_CHANGED], group);
-}
-
-void pa_audio_group_add_volume_stream(pa_audio_group *group, pas_stream *stream) {
- pa_assert(group);
- pa_assert(stream);
-
- pa_assert_se(pa_hashmap_put(group->volume_streams, stream, stream) >= 0);
-}
-
-void pa_audio_group_remove_volume_stream(pa_audio_group *group, pas_stream *stream) {
- pa_assert(group);
- pa_assert(stream);
-
- pa_assert_se(pa_hashmap_remove(group->volume_streams, stream));
-}
-
-void pa_audio_group_add_mute_stream(pa_audio_group *group, pas_stream *stream) {
- pa_assert(group);
- pa_assert(stream);
-
- pa_assert_se(pa_hashmap_put(group->mute_streams, stream, stream) >= 0);
-}
-
-void pa_audio_group_remove_mute_stream(pa_audio_group *group, pas_stream *stream) {
- pa_assert(group);
- pa_assert(stream);
-
- pa_assert_se(pa_hashmap_remove(group->mute_streams, stream));
-}
+++ /dev/null
-#ifndef fooaudiogrouphfoo
-#define fooaudiogrouphfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <modules/volume-api/mute-control.h>
-#include <modules/volume-api/volume-control.h>
-
-#include <pulse/proplist.h>
-
-#include <inttypes.h>
-
-typedef struct pa_audio_group pa_audio_group;
-
-struct pa_audio_group {
- pa_volume_api *volume_api;
- uint32_t index;
- const char *name;
- char *description;
- pa_proplist *proplist;
- pa_volume_control *volume_control;
- pa_mute_control *mute_control;
-
- pa_hashmap *volume_streams; /* pas_stream -> pas_stream (hashmap-as-a-set) */
- pa_hashmap *mute_streams; /* pas_stream -> pas_stream (hashmap-as-a-set) */
-
- bool linked;
- bool unlinked;
-};
-
-int pa_audio_group_new(pa_volume_api *api, const char *name, pa_audio_group **_r);
-void pa_audio_group_put(pa_audio_group *group);
-void pa_audio_group_unlink(pa_audio_group *group);
-void pa_audio_group_free(pa_audio_group *group);
-
-/* Called by the audio group implementation. */
-void pa_audio_group_set_description(pa_audio_group *group, const char *description);
-void pa_audio_group_set_volume_control(pa_audio_group *group, pa_volume_control *control);
-void pa_audio_group_set_mute_control(pa_audio_group *group, pa_mute_control *control);
-
-/* Called by sstream.c only. If you want to assign a stream to an audio group, use
- * pas_stream_set_audio_group_for_volume() and
- * pas_stream_set_audio_group_for_mute(). */
-void pa_audio_group_add_volume_stream(pa_audio_group *group, pas_stream *stream);
-void pa_audio_group_remove_volume_stream(pa_audio_group *group, pas_stream *stream);
-void pa_audio_group_add_mute_stream(pa_audio_group *group, pas_stream *stream);
-void pa_audio_group_remove_mute_stream(pa_audio_group *group, pas_stream *stream);
-
-#endif
+++ /dev/null
-#ifndef foobvolumehfoo
-#define foobvolumehfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <pulse/ext-volume-api.h>
-
-typedef pa_ext_volume_api_bvolume pa_bvolume;
-
-#define pa_balance_valid pa_ext_volume_api_balance_valid
-#define pa_bvolume_valid pa_ext_volume_api_bvolume_valid
-#define pa_bvolume_init_invalid pa_ext_volume_api_bvolume_init_invalid
-#define pa_bvolume_init pa_ext_volume_api_bvolume_init
-#define pa_bvolume_init_mono pa_ext_volume_api_bvolume_init_mono
-#define pa_bvolume_parse_balance pa_ext_volume_api_bvolume_parse_balance
-#define pa_bvolume_equal pa_ext_volume_api_bvolume_equal
-#define pa_bvolume_from_cvolume pa_ext_volume_api_bvolume_from_cvolume
-#define pa_bvolume_to_cvolume pa_ext_volume_api_bvolume_to_cvolume
-#define pa_bvolume_copy_balance pa_ext_volume_api_bvolume_copy_balance
-#define pa_bvolume_reset_balance pa_ext_volume_api_bvolume_reset_balance
-#define pa_bvolume_remap pa_ext_volume_api_bvolume_remap
-#define pa_bvolume_balance_to_string pa_ext_volume_api_bvolume_balance_to_string
-
-#define PA_BVOLUME_SNPRINT_BALANCE_MAX PA_EXT_VOLUME_API_BVOLUME_SNPRINT_BALANCE_MAX
-#define pa_bvolume_snprint_balance pa_ext_volume_api_bvolume_snprint_balance
-
-#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "device-creator.h"
-
-#include <modules/volume-api/device.h>
-#include <modules/volume-api/mute-control.h>
-#include <modules/volume-api/volume-control.h>
-
-#include <pulsecore/core-util.h>
-#include <pulsecore/i18n.h>
-
-struct pa_device_creator {
- pa_volume_api *volume_api;
- pa_hashmap *devices; /* pa_device_port/pa_sink/pa_source -> struct device */
- pa_hook_slot *card_put_slot;
- pa_hook_slot *card_unlink_slot;
- pa_hook_slot *sink_put_slot;
- pa_hook_slot *sink_unlink_slot;
- pa_hook_slot *source_put_slot;
- pa_hook_slot *source_unlink_slot;
-};
-
-enum device_type {
- DEVICE_TYPE_PORT,
- DEVICE_TYPE_PORT_MONITOR,
- DEVICE_TYPE_SINK,
- DEVICE_TYPE_SOURCE,
-};
-
-struct device_volume_control {
- struct device *device;
- pa_volume_control *volume_control;
-
- bool unlinked;
-
- pa_hook_slot *volume_changed_slot;
-};
-
-static void device_volume_control_free(struct device_volume_control *control);
-
-struct device_mute_control {
- struct device *device;
- pa_mute_control *mute_control;
-
- bool unlinked;
-
- pa_hook_slot *mute_changed_slot;
-};
-
-static void device_mute_control_free(struct device_mute_control *control);
-
-struct device {
- pa_device_creator *creator;
- enum device_type type;
- pa_device_port *port;
- pa_sink *sink;
- pa_source *source;
- pa_device *device;
- struct device_volume_control *volume_control;
- struct device_mute_control *mute_control;
-
- bool unlinked;
-
- pa_hook_slot *proplist_changed_slot;
- pa_hook_slot *port_active_changed_slot;
- struct device *monitor;
-};
-
-static void device_free(struct device *device);
-
-static const char *device_type_from_icon_name(const char *icon_name) {
- if (!icon_name)
- return NULL;
-
- if (pa_streq(icon_name, "audio-input-microphone"))
- return "microphone";
-
- if (pa_streq(icon_name, "audio-speakers"))
- return "speakers";
-
- if (pa_streq(icon_name, "audio-headphones"))
- return "headphones";
-
- return NULL;
-}
-
-static const char *device_type_from_port_name(pa_device_port *port) {
- pa_assert(port);
-
- if (strstr(port->name, "analog")) {
- if (port->direction == PA_DIRECTION_INPUT)
- return "analog-input";
- else
- return "analog-output";
- }
-
- if (strstr(port->name, "hdmi")) {
- if (port->direction == PA_DIRECTION_INPUT)
- return "hdmi-input";
- else
- return "hdmi-output";
- }
-
- if (strstr(port->name, "iec958")) {
- if (port->direction == PA_DIRECTION_INPUT)
- return "spdif-input";
- else
- return "spdif-output";
- }
-
- return NULL;
-}
-
-static const char *device_type_from_port(pa_device_port *port) {
- const char *device_type;
-
- pa_assert(port);
-
- device_type = device_type_from_icon_name(pa_proplist_gets(port->proplist, PA_PROP_DEVICE_ICON_NAME));
- if (device_type)
- return device_type;
-
- device_type = device_type_from_port_name(port);
- if (device_type)
- return device_type;
-
- return NULL;
-}
-
-static const char *get_sink_description(pa_sink *sink) {
- const char *description;
-
- pa_assert(sink);
-
- description = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION);
- if (description)
- return description;
-
- return sink->name;
-}
-
-static const char *get_source_description(pa_source *source) {
- const char *description;
-
- pa_assert(source);
-
- description = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION);
- if (description)
- return description;
-
- return source->name;
-}
-
-static pa_hook_result_t sink_or_source_volume_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct device_volume_control *control = userdata;
- struct device *device;
- pa_sink *sink = NULL;
- pa_source *source = NULL;
- pa_bvolume bvolume;
-
- pa_assert(control);
- pa_assert(call_data);
-
- device = control->device;
-
- switch (device->type) {
- case DEVICE_TYPE_PORT:
- if (device->port->direction == PA_DIRECTION_OUTPUT)
- sink = call_data;
- else
- source = call_data;
- break;
-
- case DEVICE_TYPE_PORT_MONITOR:
- case DEVICE_TYPE_SOURCE:
- source = call_data;
- break;
-
- case DEVICE_TYPE_SINK:
- sink = call_data;
- break;
- }
-
- if ((sink && sink != device->sink) || (source && source != device->source))
- return PA_HOOK_OK;
-
- if (sink)
- pa_bvolume_from_cvolume(&bvolume, &sink->reference_volume, &sink->channel_map);
- else if (source)
- pa_bvolume_from_cvolume(&bvolume, &source->reference_volume, &source->channel_map);
- else
- pa_assert_not_reached();
-
- pa_volume_control_set_volume(control->volume_control, &bvolume, true, true);
-
- return PA_HOOK_OK;
-}
-
-static int volume_control_set_volume_cb(pa_volume_control *c, const pa_bvolume *original_volume,
- const pa_bvolume *remapped_volume, bool set_volume, bool set_balance) {
- struct device_volume_control *control;
- struct device *device;
- pa_bvolume bvolume;
- pa_cvolume cvolume;
-
- pa_assert(c);
- pa_assert(original_volume);
- pa_assert(remapped_volume);
-
- control = c->userdata;
- device = control->device;
-
- switch (device->type) {
- case DEVICE_TYPE_PORT:
- if (device->port->direction == PA_DIRECTION_OUTPUT)
- pa_bvolume_from_cvolume(&bvolume, &device->sink->reference_volume, &device->sink->channel_map);
- else
- pa_bvolume_from_cvolume(&bvolume, &device->source->reference_volume, &device->source->channel_map);
- break;
-
- case DEVICE_TYPE_SINK:
- pa_bvolume_from_cvolume(&bvolume, &device->sink->reference_volume, &device->sink->channel_map);
- break;
-
- case DEVICE_TYPE_PORT_MONITOR:
- case DEVICE_TYPE_SOURCE:
- pa_bvolume_from_cvolume(&bvolume, &device->source->reference_volume, &device->source->channel_map);
- break;
- }
-
- if (set_volume)
- bvolume.volume = remapped_volume->volume;
-
- if (set_balance)
- pa_bvolume_copy_balance(&bvolume, remapped_volume);
-
- pa_bvolume_to_cvolume(&bvolume, &cvolume);
-
- switch (device->type) {
- case DEVICE_TYPE_PORT:
- if (device->port->direction == PA_DIRECTION_OUTPUT)
- pa_sink_set_volume(device->sink, &cvolume, true, true);
- else
- pa_source_set_volume(device->source, &cvolume, true, true);
- break;
-
- case DEVICE_TYPE_PORT_MONITOR:
- case DEVICE_TYPE_SOURCE:
- pa_source_set_volume(device->source, &cvolume, true, true);
- break;
-
- case DEVICE_TYPE_SINK:
- pa_sink_set_volume(device->sink, &cvolume, true, true);
- break;
- }
-
- return 0;
-}
-
-static int device_volume_control_new(struct device *device, struct device_volume_control **_r) {
- struct device_volume_control *control = NULL;
- const char *name = NULL;
- pa_bvolume volume;
- bool convertible_to_dB = false;
- int r;
-
- pa_assert(device);
- pa_assert(_r);
-
- control = pa_xnew0(struct device_volume_control, 1);
- control->device = device;
-
- switch (device->type) {
- case DEVICE_TYPE_PORT:
- name = "port-volume-control";
-
- if (device->port->direction == PA_DIRECTION_OUTPUT) {
- control->volume_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control);
- pa_bvolume_from_cvolume(&volume, &device->sink->reference_volume, &device->sink->channel_map);
- convertible_to_dB = device->sink->flags & PA_SINK_DECIBEL_VOLUME;
- } else {
- control->volume_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control);
- pa_bvolume_from_cvolume(&volume, &device->source->reference_volume, &device->source->channel_map);
- convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME;
- }
-
- break;
-
- case DEVICE_TYPE_PORT_MONITOR:
- name = "port-monitor-volume-control";
- control->volume_changed_slot = pa_hook_connect(&device->source->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control);
- pa_bvolume_from_cvolume(&volume, &device->source->reference_volume, &device->source->channel_map);
- convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME;
- break;
-
- case DEVICE_TYPE_SINK:
- name = "sink-volume-control";
- control->volume_changed_slot = pa_hook_connect(&device->sink->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control);
- pa_bvolume_from_cvolume(&volume, &device->sink->reference_volume, &device->sink->channel_map);
- convertible_to_dB = device->sink->flags & PA_SINK_DECIBEL_VOLUME;
- break;
-
- case DEVICE_TYPE_SOURCE:
- name = "source-volume-control";
- control->volume_changed_slot = pa_hook_connect(&device->source->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control);
- pa_bvolume_from_cvolume(&volume, &device->source->reference_volume, &device->source->channel_map);
- convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME;
- break;
- }
-
- r = pa_volume_control_new(device->creator->volume_api, name, false, &control->volume_control);
- if (r < 0)
- goto fail;
-
- pa_volume_control_set_description(control->volume_control, device->device->description);
- pa_volume_control_set_channel_map(control->volume_control, &volume.channel_map);
- pa_volume_control_set_volume(control->volume_control, &volume, true, true);
- pa_volume_control_set_convertible_to_dB(control->volume_control, convertible_to_dB);
- control->volume_control->set_volume = volume_control_set_volume_cb;
- control->volume_control->userdata = control;
-
- *_r = control;
- return 0;
-
-fail:
- if (control)
- device_volume_control_free(control);
-
- return r;
-}
-
-static void device_volume_control_put(struct device_volume_control *control) {
- pa_assert(control);
-
- pa_volume_control_put(control->volume_control);
-}
-
-static void device_volume_control_unlink(struct device_volume_control *control) {
- pa_assert(control);
-
- if (control->unlinked)
- return;
-
- control->unlinked = true;
-
- if (control->volume_control)
- pa_volume_control_unlink(control->volume_control);
-}
-
-static void device_volume_control_free(struct device_volume_control *control) {
- pa_assert(control);
-
- if (!control->unlinked)
- device_volume_control_unlink(control);
-
- if (control->volume_control)
- pa_volume_control_free(control->volume_control);
-
- if (control->volume_changed_slot)
- pa_hook_slot_free(control->volume_changed_slot);
-
- pa_xfree(control);
-}
-
-static pa_hook_result_t sink_or_source_mute_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct device_mute_control *control = userdata;
- struct device *device;
- pa_sink *sink = NULL;
- pa_source *source = NULL;
- bool mute;
-
- pa_assert(control);
- pa_assert(call_data);
-
- device = control->device;
-
- switch (device->type) {
- case DEVICE_TYPE_PORT:
- if (device->port->direction == PA_DIRECTION_OUTPUT)
- sink = call_data;
- else
- source = call_data;
- break;
-
- case DEVICE_TYPE_PORT_MONITOR:
- case DEVICE_TYPE_SOURCE:
- source = call_data;
- break;
-
- case DEVICE_TYPE_SINK:
- sink = call_data;
- break;
- }
-
- if ((sink && sink != device->sink) || (source && source != device->source))
- return PA_HOOK_OK;
-
- if (sink)
- mute = sink->muted;
- else if (source)
- mute = source->muted;
- else
- pa_assert_not_reached();
-
- pa_mute_control_set_mute(control->mute_control, mute);
-
- return PA_HOOK_OK;
-}
-
-static int mute_control_set_mute_cb(pa_mute_control *c, bool mute) {
- struct device_mute_control *control;
- struct device *device;
-
- pa_assert(c);
-
- control = c->userdata;
- device = control->device;
-
- switch (device->type) {
- case DEVICE_TYPE_PORT:
- if (device->port->direction == PA_DIRECTION_OUTPUT)
- pa_sink_set_mute(device->sink, mute, true);
- else
- pa_source_set_mute(device->source, mute, true);
- break;
-
- case DEVICE_TYPE_PORT_MONITOR:
- case DEVICE_TYPE_SOURCE:
- pa_source_set_mute(device->source, mute, true);
- break;
-
- case DEVICE_TYPE_SINK:
- pa_sink_set_mute(device->sink, mute, true);
- break;
- }
-
- return 0;
-}
-
-static int device_mute_control_new(struct device *device, struct device_mute_control **_r) {
- struct device_mute_control *control = NULL;
- const char *name = NULL;
- bool mute = false;
- int r;
-
- pa_assert(device);
- pa_assert(_r);
-
- control = pa_xnew0(struct device_mute_control, 1);
- control->device = device;
-
- switch (device->type) {
- case DEVICE_TYPE_PORT:
- name = "port-mute-control";
-
- if (device->port->direction == PA_DIRECTION_OUTPUT) {
- control->mute_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SINK_MUTE_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control);
- mute = device->sink->muted;
- } else {
- control->mute_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SOURCE_MUTE_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control);
- mute = device->source->muted;
- }
- break;
-
- case DEVICE_TYPE_PORT_MONITOR:
- name = "port-monitor-mute-control";
- control->mute_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SOURCE_MUTE_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control);
- mute = device->source->muted;
- break;
-
- case DEVICE_TYPE_SINK:
- name = "sink-mute-control";
- control->mute_changed_slot = pa_hook_connect(&device->sink->core->hooks[PA_CORE_HOOK_SINK_MUTE_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control);
- mute = device->sink->muted;
- break;
-
- case DEVICE_TYPE_SOURCE:
- name = "source-mute-control";
- control->mute_changed_slot = pa_hook_connect(&device->source->core->hooks[PA_CORE_HOOK_SOURCE_MUTE_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control);
- mute = device->source->muted;
- break;
- }
-
- r = pa_mute_control_new(device->creator->volume_api, name, false, &control->mute_control);
- if (r < 0)
- goto fail;
-
- pa_mute_control_set_description(control->mute_control, device->device->description);
- pa_mute_control_set_mute(control->mute_control, mute);
- control->mute_control->set_mute = mute_control_set_mute_cb;
- control->mute_control->userdata = control;
-
- *_r = control;
- return 0;
-
-fail:
- if (control)
- device_mute_control_free(control);
-
- return r;
-}
-
-static void device_mute_control_put(struct device_mute_control *control) {
- pa_assert(control);
-
- pa_mute_control_put(control->mute_control);
-}
-
-static void device_mute_control_unlink(struct device_mute_control *control) {
- pa_assert(control);
-
- if (control->unlinked)
- return;
-
- control->unlinked = true;
-
- if (control->mute_control)
- pa_mute_control_unlink(control->mute_control);
-}
-
-static void device_mute_control_free(struct device_mute_control *control) {
- pa_assert(control);
-
- if (!control->unlinked)
- device_mute_control_unlink(control);
-
- if (control->mute_control)
- pa_mute_control_free(control->mute_control);
-
- if (control->mute_changed_slot)
- pa_hook_slot_free(control->mute_changed_slot);
-
- pa_xfree(control);
-}
-
-static void device_set_sink_and_source_from_port(struct device *device) {
- pa_sink *sink;
- pa_source *source;
- uint32_t idx;
-
- pa_assert(device);
-
- device->sink = NULL;
- device->source = NULL;
-
- if (!device->port->active)
- return;
-
- switch (device->type) {
- case DEVICE_TYPE_PORT:
- if (device->port->direction == PA_DIRECTION_OUTPUT) {
- PA_IDXSET_FOREACH(sink, device->port->card->sinks, idx) {
- if (sink->active_port == device->port) {
- device->sink = sink;
- break;
- }
- }
-
- pa_assert(device->sink);
- } else {
- PA_IDXSET_FOREACH(source, device->port->card->sources, idx) {
- if (source->active_port == device->port) {
- device->source = source;
- break;
- }
- }
-
- pa_assert(device->source);
- }
- break;
-
- case DEVICE_TYPE_PORT_MONITOR: {
- PA_IDXSET_FOREACH(sink, device->port->card->sinks, idx) {
- if (sink->active_port == device->port) {
- device->sink = sink;
- device->source = sink->monitor_source;
- break;
- }
- }
-
- pa_assert(device->sink);
- break;
- }
-
- case DEVICE_TYPE_SINK:
- case DEVICE_TYPE_SOURCE:
- pa_assert_not_reached();
- }
-}
-
-static pa_hook_result_t sink_or_source_proplist_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct device *device = userdata;
- pa_sink *sink = NULL;
- pa_source *source = NULL;
- const char *description = NULL;
-
- pa_assert(device);
- pa_assert(call_data);
-
- switch (device->type) {
- case DEVICE_TYPE_PORT:
- case DEVICE_TYPE_PORT_MONITOR:
- pa_assert_not_reached();
-
- case DEVICE_TYPE_SINK:
- sink = call_data;
-
- if (sink != device->sink)
- return PA_HOOK_OK;
-
- description = get_sink_description(sink);
- break;
-
- case DEVICE_TYPE_SOURCE:
- source = call_data;
-
- if (source != device->source)
- return PA_HOOK_OK;
-
- description = get_source_description(source);
- break;
- }
-
- pa_device_description_changed(device->device, description);
- pa_volume_control_set_description(device->volume_control->volume_control, description);
- pa_mute_control_set_description(device->mute_control->mute_control, description);
-
- return PA_HOOK_OK;
-}
-
-static int device_new(pa_device_creator *creator, enum device_type type, void *core_device, struct device **_r) {
- struct device *device = NULL;
- const char *name = NULL;
- char *description = NULL;
- pa_direction_t direction = PA_DIRECTION_OUTPUT;
- const char *device_type = NULL;
- bool create_volume_and_mute_controls = true;
- int r;
-
- pa_assert(creator);
- pa_assert(core_device);
- pa_assert(_r);
-
- device = pa_xnew0(struct device, 1);
- device->creator = creator;
- device->type = type;
-
- switch (type) {
- case DEVICE_TYPE_PORT:
- device->port = core_device;
- device_set_sink_and_source_from_port(device);
- name = "port-device";
- description = pa_xstrdup(device->port->description);
- direction = device->port->direction;
- device_type = device_type_from_port(device->port);
-
- if (!device->sink && !device->source)
- create_volume_and_mute_controls = false;
- break;
-
- case DEVICE_TYPE_PORT_MONITOR:
- device->port = core_device;
- device_set_sink_and_source_from_port(device);
- name = "port-monitor-device";
- description = pa_sprintf_malloc(_("Monitor of %s"), device->port->description);
- direction = PA_DIRECTION_INPUT;
-
- if (!device->source)
- create_volume_and_mute_controls = false;
- break;
-
- case DEVICE_TYPE_SINK:
- device->sink = core_device;
- name = "sink-device";
- description = pa_xstrdup(get_sink_description(device->sink));
- direction = PA_DIRECTION_OUTPUT;
- break;
-
- case DEVICE_TYPE_SOURCE:
- device->source = core_device;
- name = "source-device";
- description = pa_xstrdup(get_source_description(device->source));
- direction = PA_DIRECTION_INPUT;
- break;
- }
-
- r = pa_device_new(creator->volume_api, name, description, direction, &device_type, device_type ? 1 : 0, &device->device);
- pa_xfree(description);
- if (r < 0)
- goto fail;
-
- if (create_volume_and_mute_controls) {
- device_volume_control_new(device, &device->volume_control);
- device_mute_control_new(device, &device->mute_control);
- }
-
- switch (type) {
- case DEVICE_TYPE_PORT:
- if (device->port->direction == PA_DIRECTION_OUTPUT)
- device_new(creator, DEVICE_TYPE_PORT_MONITOR, device->port, &device->monitor);
- break;
-
- case DEVICE_TYPE_PORT_MONITOR:
- break;
-
- case DEVICE_TYPE_SINK:
- device->proplist_changed_slot = pa_hook_connect(&device->sink->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_proplist_changed_cb, device);
- break;
-
- case DEVICE_TYPE_SOURCE:
- device->proplist_changed_slot = pa_hook_connect(&device->source->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED],
- PA_HOOK_NORMAL, sink_or_source_proplist_changed_cb, device);
- break;
- }
-
- *_r = device;
- return 0;
-
-fail:
- if (device)
- device_free(device);
-
- return r;
-}
-
-static pa_hook_result_t port_active_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct device *device = userdata;
- pa_device_port *port = call_data;
- bool should_have_volume_and_mute_controls = false;
-
- pa_assert(device);
- pa_assert(port);
-
- if (port != device->port)
- return PA_HOOK_OK;
-
- device_set_sink_and_source_from_port(device);
-
- switch (device->type) {
- case DEVICE_TYPE_PORT:
- should_have_volume_and_mute_controls = device->sink || device->source;
- break;
-
- case DEVICE_TYPE_PORT_MONITOR:
- should_have_volume_and_mute_controls = !!device->source;
- break;
-
- case DEVICE_TYPE_SINK:
- case DEVICE_TYPE_SOURCE:
- pa_assert_not_reached();
- }
-
- if (should_have_volume_and_mute_controls) {
- int r;
-
- if (!device->volume_control) {
- r = device_volume_control_new(device, &device->volume_control);
- if (r >= 0) {
- device_volume_control_put(device->volume_control);
- pa_device_set_default_volume_control(device->device, device->volume_control->volume_control);
- }
- }
-
- if (!device->mute_control) {
- r = device_mute_control_new(device, &device->mute_control);
- if (r >= 0) {
- device_mute_control_put(device->mute_control);
- pa_device_set_default_mute_control(device->device, device->mute_control->mute_control);
- }
- }
- }
-
- if (!should_have_volume_and_mute_controls) {
- if (device->mute_control) {
- device_mute_control_free(device->mute_control);
- device->mute_control = NULL;
- }
-
- if (device->volume_control) {
- device_volume_control_free(device->volume_control);
- device->volume_control = NULL;
- }
- }
-
- return PA_HOOK_OK;
-}
-
-static void device_put(struct device *device) {
- pa_assert(device);
-
- switch (device->type) {
- case DEVICE_TYPE_PORT:
- case DEVICE_TYPE_PORT_MONITOR:
- device->port_active_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_PORT_ACTIVE_CHANGED],
- PA_HOOK_NORMAL, port_active_changed_cb, device);
-
- case DEVICE_TYPE_SINK:
- case DEVICE_TYPE_SOURCE:
- break;
- }
-
- if (device->volume_control)
- device_volume_control_put(device->volume_control);
-
- if (device->mute_control)
- device_mute_control_put(device->mute_control);
-
- pa_device_put(device->device, device->volume_control ? device->volume_control->volume_control : NULL,
- device->mute_control ? device->mute_control->mute_control : NULL);
-
- if (device->monitor)
- device_put(device->monitor);
-}
-
-static void device_unlink(struct device *device) {
- pa_assert(device);
-
- if (device->unlinked)
- return;
-
- device->unlinked = true;
-
- if (device->monitor)
- device_unlink(device->monitor);
-
- if (device->device)
- pa_device_unlink(device->device);
-
- if (device->mute_control)
- device_mute_control_unlink(device->mute_control);
-
- if (device->volume_control)
- device_volume_control_unlink(device->volume_control);
-
- if (device->port_active_changed_slot) {
- pa_hook_slot_free(device->port_active_changed_slot);
- device->port_active_changed_slot = NULL;
- }
-}
-
-static void device_free(struct device *device) {
- pa_assert(device);
-
- if (!device->unlinked)
- device_unlink(device);
-
- if (device->monitor)
- device_free(device->monitor);
-
- if (device->proplist_changed_slot)
- pa_hook_slot_free(device->proplist_changed_slot);
-
- if (device->mute_control)
- device_mute_control_free(device->mute_control);
-
- if (device->volume_control)
- device_volume_control_free(device->volume_control);
-
- if (device->device)
- pa_device_free(device->device);
-
- pa_xfree(device);
-}
-
-static void create_device(pa_device_creator *creator, enum device_type type, void *core_device) {
- struct device *device;
- int r;
-
- pa_assert(creator);
- pa_assert(core_device);
-
- switch (type) {
- case DEVICE_TYPE_PORT:
- break;
-
- case DEVICE_TYPE_PORT_MONITOR:
- pa_assert_not_reached();
-
- case DEVICE_TYPE_SINK:
- if (!pa_hashmap_isempty(((pa_sink *) core_device)->ports))
- return;
- break;
-
- case DEVICE_TYPE_SOURCE: {
- pa_source *source = core_device;
-
- if (source->monitor_of && !pa_hashmap_isempty(source->monitor_of->ports))
- return;
-
- if (!pa_hashmap_isempty(((pa_source *) core_device)->ports))
- return;
- break;
- }
- }
-
- r = device_new(creator, type, core_device, &device);
- if (r >= 0) {
- pa_hashmap_put(creator->devices, core_device, device);
- device_put(device);
- }
-}
-
-static pa_hook_result_t card_put_cb(void *hook_data, void *call_data, void *userdata) {
- pa_device_creator *creator = userdata;
- pa_card *card = call_data;
- pa_device_port *port;
- void *state;
-
- pa_assert(creator);
- pa_assert(card);
-
- PA_HASHMAP_FOREACH(port, card->ports, state)
- create_device(creator, DEVICE_TYPE_PORT, port);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t card_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- pa_device_creator *creator = userdata;
- pa_card *card = call_data;
- pa_device_port *port;
- void *state;
-
- pa_assert(creator);
- pa_assert(card);
-
- PA_HASHMAP_FOREACH(port, card->ports, state)
- pa_hashmap_remove_and_free(creator->devices, port);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t sink_put_cb(void *hook_data, void *call_data, void *userdata) {
- pa_device_creator *creator = userdata;
- pa_sink *sink = call_data;
-
- pa_assert(creator);
- pa_assert(sink);
-
- create_device(creator, DEVICE_TYPE_SINK, sink);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t sink_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- pa_device_creator *creator = userdata;
- pa_sink *sink = call_data;
-
- pa_assert(creator);
- pa_assert(sink);
-
- pa_hashmap_remove_and_free(creator->devices, sink);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t source_put_cb(void *hook_data, void *call_data, void *userdata) {
- pa_device_creator *creator = userdata;
- pa_source *source = call_data;
-
- pa_assert(creator);
- pa_assert(source);
-
- create_device(creator, DEVICE_TYPE_SOURCE, source);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t source_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- pa_device_creator *creator = userdata;
- pa_source *source = call_data;
-
- pa_assert(creator);
- pa_assert(source);
-
- pa_hashmap_remove_and_free(creator->devices, source);
-
- return PA_HOOK_OK;
-}
-
-pa_device_creator *pa_device_creator_new(pa_volume_api *api) {
- pa_device_creator *creator;
- pa_card *card;
- uint32_t idx;
- pa_sink *sink;
- pa_source *source;
-
- pa_assert(api);
-
- creator = pa_xnew0(pa_device_creator, 1);
- creator->volume_api = api;
- creator->devices = pa_hashmap_new_full(NULL, NULL, NULL, (pa_free_cb_t) device_free);
- creator->card_put_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_CARD_PUT], PA_HOOK_NORMAL, card_put_cb, creator);
- creator->card_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_CARD_UNLINK], PA_HOOK_NORMAL, card_unlink_cb,
- creator);
- creator->sink_put_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL, sink_put_cb, creator);
- creator->sink_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_NORMAL, sink_unlink_cb,
- creator);
- creator->source_put_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_NORMAL, source_put_cb,
- creator);
- creator->source_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_NORMAL,
- source_unlink_cb, creator);
-
- PA_IDXSET_FOREACH(card, api->core->cards, idx) {
- pa_device_port *port;
- void *state;
-
- PA_HASHMAP_FOREACH(port, card->ports, state)
- create_device(creator, DEVICE_TYPE_PORT, port);
- }
-
- PA_IDXSET_FOREACH(sink, api->core->sinks, idx)
- create_device(creator, DEVICE_TYPE_SINK, sink);
-
- PA_IDXSET_FOREACH(source, api->core->sources, idx)
- create_device(creator, DEVICE_TYPE_SOURCE, source);
-
- return creator;
-}
-
-void pa_device_creator_free(pa_device_creator *creator) {
- pa_assert(creator);
-
- if (creator->devices)
- pa_hashmap_remove_all(creator->devices);
-
- if (creator->source_unlink_slot)
- pa_hook_slot_free(creator->source_unlink_slot);
-
- if (creator->source_put_slot)
- pa_hook_slot_free(creator->source_put_slot);
-
- if (creator->sink_unlink_slot)
- pa_hook_slot_free(creator->sink_unlink_slot);
-
- if (creator->sink_put_slot)
- pa_hook_slot_free(creator->sink_put_slot);
-
- if (creator->card_unlink_slot)
- pa_hook_slot_free(creator->card_unlink_slot);
-
- if (creator->card_put_slot)
- pa_hook_slot_free(creator->card_put_slot);
-
- if (creator->devices)
- pa_hashmap_free(creator->devices);
-
- pa_xfree(creator);
-}
+++ /dev/null
-#ifndef foodevicecreatorhfoo
-#define foodevicecreatorhfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <modules/volume-api/volume-api.h>
-
-typedef struct pa_device_creator pa_device_creator;
-
-pa_device_creator *pa_device_creator_new(pa_volume_api *api);
-void pa_device_creator_free(pa_device_creator *creator);
-
-#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "device.h"
-
-#include <modules/volume-api/mute-control.h>
-#include <modules/volume-api/volume-control.h>
-
-#include <pulse/direction.h>
-
-#include <pulsecore/core-util.h>
-
-int pa_device_new(pa_volume_api *api, const char *name, const char *description, pa_direction_t direction,
- const char * const *device_types, unsigned n_device_types, pa_device **_r) {
- pa_device *device = NULL;
- int r;
- unsigned i;
-
- pa_assert(api);
- pa_assert(name);
- pa_assert(description);
- pa_assert(device_types || n_device_types == 0);
- pa_assert(_r);
-
- device = pa_xnew0(pa_device, 1);
- device->volume_api = api;
- device->index = pa_volume_api_allocate_device_index(api);
-
- r = pa_volume_api_register_name(api, name, false, &device->name);
- if (r < 0)
- goto fail;
-
- device->description = pa_xstrdup(description);
- device->direction = direction;
- device->device_types = pa_dynarray_new(pa_xfree);
-
- for (i = 0; i < n_device_types; i++)
- pa_dynarray_append(device->device_types, pa_xstrdup(device_types[i]));
-
- device->proplist = pa_proplist_new();
- device->use_default_volume_control = true;
- device->use_default_mute_control = true;
-
- *_r = device;
- return 0;
-
-fail:
- if (device)
- pa_device_free(device);
-
- return r;
-}
-
-void pa_device_put(pa_device *device, pa_volume_control *default_volume_control, pa_mute_control *default_mute_control) {
- char *device_types_str;
- const char *prop_key;
- void *state = NULL;
-
- pa_assert(device);
-
- if (default_volume_control) {
- device->default_volume_control = default_volume_control;
- pa_volume_control_add_default_for_device(default_volume_control, device);
-
- device->volume_control = default_volume_control;
- pa_volume_control_add_device(default_volume_control, device);
- }
-
- if (default_mute_control) {
- device->default_mute_control = default_mute_control;
- pa_mute_control_add_default_for_device(default_mute_control, device);
-
- device->mute_control = default_mute_control;
- pa_mute_control_add_device(default_mute_control, device);
- }
-
- pa_volume_api_add_device(device->volume_api, device);
- device->linked = true;
-
- device_types_str = pa_join((const char * const *) pa_dynarray_get_raw_array(device->device_types),
- pa_dynarray_size(device->device_types), ", ");
-
- pa_log_debug("Created device #%u.", device->index);
- pa_log_debug(" Name: %s", device->name);
- pa_log_debug(" Description: %s", device->description);
- pa_log_debug(" Direction: %s", pa_direction_to_string(device->direction));
- pa_log_debug(" Device Types: %s", *device_types_str ? device_types_str : "(none)");
- pa_log_debug(" Volume control: %s", device->volume_control ? device->volume_control->name : "(unset)");
- pa_log_debug(" Mute control: %s", device->mute_control ? device->mute_control->name : "(unset)");
- pa_log_debug(" Properties:");
-
- while ((prop_key = pa_proplist_iterate(device->proplist, &state)))
- pa_log_debug(" %s = %s", prop_key, pa_strnull(pa_proplist_gets(device->proplist, prop_key)));
-
- pa_xfree(device_types_str);
-
- pa_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_PUT], device);
-}
-
-void pa_device_unlink(pa_device *device) {
- pa_assert(device);
-
- if (device->unlinked) {
- pa_log_debug("Unlinking device %s (already unlinked, this is a no-op).", device->name);
- return;
- }
-
- device->unlinked = true;
-
- pa_log_debug("Unlinking device %s.", device->name);
-
- if (device->linked)
- pa_volume_api_remove_device(device->volume_api, device);
-
- pa_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_UNLINK], device);
-
- pa_device_set_mute_control(device, NULL);
- pa_device_set_default_mute_control(device, NULL);
- pa_device_set_volume_control(device, NULL);
- pa_device_set_default_volume_control(device, NULL);
-}
-
-void pa_device_free(pa_device *device) {
- pa_assert(device);
-
- /* unlink() expects name to be set. */
- if (!device->unlinked && device->name)
- pa_device_unlink(device);
-
- if (device->proplist)
- pa_proplist_free(device->proplist);
-
- if (device->device_types)
- pa_dynarray_free(device->device_types);
-
- pa_xfree(device->description);
-
- if (device->name)
- pa_volume_api_unregister_name(device->volume_api, device->name);
-
- pa_xfree(device);
-}
-
-static void set_volume_control_internal(pa_device *device, pa_volume_control *control) {
- pa_volume_control *old_control;
-
- pa_assert(device);
-
- old_control = device->volume_control;
-
- if (control == old_control)
- return;
-
- if (old_control)
- pa_volume_control_remove_device(old_control, device);
-
- device->volume_control = control;
-
- if (control)
- pa_volume_control_add_device(control, device);
-
- if (!device->linked || device->unlinked)
- return;
-
- pa_log_debug("The volume control of device %s changed from %s to %s.", device->name,
- old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-
- pa_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_VOLUME_CONTROL_CHANGED], device);
-}
-
-void pa_device_set_volume_control(pa_device *device, pa_volume_control *control) {
- pa_assert(device);
-
- device->use_default_volume_control = false;
- set_volume_control_internal(device, control);
-}
-
-static void set_mute_control_internal(pa_device *device, pa_mute_control *control) {
- pa_mute_control *old_control;
-
- pa_assert(device);
-
- old_control = device->mute_control;
-
- if (control == old_control)
- return;
-
- if (old_control)
- pa_mute_control_remove_device(old_control, device);
-
- device->mute_control = control;
-
- if (control)
- pa_mute_control_add_device(control, device);
-
- pa_log_debug("The mute control of device %s changed from %s to %s.", device->name,
- old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-
- pa_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_MUTE_CONTROL_CHANGED], device);
-}
-
-void pa_device_set_mute_control(pa_device *device, pa_mute_control *control) {
- pa_assert(device);
-
- device->use_default_mute_control = false;
- set_mute_control_internal(device, control);
-}
-
-void pa_device_description_changed(pa_device *device, const char *new_description) {
- char *old_description;
-
- pa_assert(device);
- pa_assert(new_description);
-
- old_description = device->description;
-
- if (pa_streq(new_description, old_description))
- return;
-
- device->description = pa_xstrdup(new_description);
- pa_log_debug("The description of device %s changed from \"%s\" to \"%s\".", device->name, old_description,
- new_description);
- pa_xfree(old_description);
- pa_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_DESCRIPTION_CHANGED], device);
-}
-
-void pa_device_set_default_volume_control(pa_device *device, pa_volume_control *control) {
- pa_volume_control *old_control;
-
- pa_assert(device);
-
- old_control = device->default_volume_control;
-
- if (control == old_control)
- return;
-
- if (old_control)
- pa_volume_control_remove_default_for_device(old_control, device);
-
- device->default_volume_control = control;
-
- if (control)
- pa_volume_control_add_default_for_device(control, device);
-
- if (device->use_default_volume_control)
- set_volume_control_internal(device, control);
-}
-
-void pa_device_set_default_mute_control(pa_device *device, pa_mute_control *control) {
- pa_mute_control *old_control;
-
- pa_assert(device);
-
- old_control = device->default_mute_control;
-
- if (control == old_control)
- return;
-
- if (old_control)
- pa_mute_control_remove_default_for_device(old_control, device);
-
- device->default_mute_control = control;
-
- if (control)
- pa_mute_control_add_default_for_device(control, device);
-
- if (device->use_default_mute_control)
- set_mute_control_internal(device, control);
-}
+++ /dev/null
-#ifndef foodevicehfoo
-#define foodevicehfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <modules/volume-api/volume-api.h>
-
-#include <pulsecore/dynarray.h>
-
-typedef struct pa_device pa_device;
-
-struct pa_device {
- pa_volume_api *volume_api;
- uint32_t index;
- const char *name;
- char *description;
- pa_direction_t direction;
- pa_dynarray *device_types;
- pa_proplist *proplist;
- pa_volume_control *volume_control;
- pa_mute_control *mute_control;
-
- /* The device implementation can provide default volume and mute controls,
- * which are used in case there's no policy module that wants to override
- * the defaults. */
- pa_volume_control *default_volume_control;
- bool use_default_volume_control;
- pa_mute_control *default_mute_control;
- bool use_default_mute_control;
-
- bool linked;
- bool unlinked;
-};
-
-int pa_device_new(pa_volume_api *api, const char *name, const char *description, pa_direction_t direction,
- const char * const *device_types, unsigned n_device_types, pa_device **_r);
-void pa_device_put(pa_device *device, pa_volume_control *default_volume_control, pa_mute_control *default_mute_control);
-void pa_device_unlink(pa_device *device);
-void pa_device_free(pa_device *device);
-
-/* Called by policy modules. */
-void pa_device_set_volume_control(pa_device *device, pa_volume_control *control);
-void pa_device_set_mute_control(pa_device *device, pa_mute_control *control);
-
-/* Called by policy modules. Note that pa_device_set_volume_control() and
- * pa_device_set_mute_control() automatically disable the corresponding
- * use_default flags, so these functions are mainly useful for re-enabling the
- * flags. */
-void pa_device_set_use_default_volume_control(pa_device *device, bool use);
-void pa_device_set_use_default_mute_control(pa_device *device, bool use);
-
-/* Called by the device implementation. */
-void pa_device_description_changed(pa_device *device, const char *new_description);
-void pa_device_set_default_volume_control(pa_device *device, pa_volume_control *control);
-void pa_device_set_default_mute_control(pa_device *device, pa_mute_control *control);
-
-#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "inidb.h"
-
-#include <pulse/mainloop-api.h>
-#include <pulse/rtclock.h>
-#include <pulse/timeval.h>
-#include <pulse/xmalloc.h>
-
-#include <pulsecore/conf-parser.h>
-#include <pulsecore/core-error.h>
-#include <pulsecore/core-rtclock.h>
-#include <pulsecore/core-util.h>
-#include <pulsecore/hashmap.h>
-#include <pulsecore/macro.h>
-#include <pulsecore/namereg.h>
-
-#include <errno.h>
-
-#define SAVE_INTERVAL_USEC (10 * PA_USEC_PER_SEC)
-
-struct pa_inidb {
- pa_core *core;
- char *name;
- char *file_path;
- char *tmp_file_path;
- pa_hashmap *tables; /* table name -> pa_inidb_table */
- pa_time_event *time_event;
- bool failed;
- void *userdata;
-};
-
-struct pa_inidb_table {
- pa_inidb *db;
- char *name;
- pa_hashmap *columns; /* column name -> column */
- pa_hashmap *rows; /* row id -> pa_inidb_row */
- pa_inidb_get_object_cb_t get_object;
-};
-
-struct column {
- char *name;
- pa_inidb_parse_cb_t parse;
-};
-
-struct pa_inidb_row {
- char *id;
- char *header;
- pa_hashmap *cells; /* column name -> cell */
-};
-
-struct pa_inidb_cell {
- pa_inidb *db;
- struct column *column;
- char *value;
- char *assignment;
-};
-
-static void save(pa_inidb *db);
-
-static pa_inidb_table *table_new(pa_inidb *db, const char *name, pa_inidb_get_object_cb_t get_object_cb);
-static void table_free(pa_inidb_table *table);
-static pa_inidb_row *table_add_row_internal(pa_inidb_table *table, const char *row_id);
-
-static struct column *column_new(const char *name, pa_inidb_parse_cb_t parse_cb);
-static void column_free(struct column *column);
-
-static pa_inidb_row *row_new(pa_inidb_table *table, const char *id);
-static void row_free(pa_inidb_row *row);
-
-static pa_inidb_cell *cell_new(pa_inidb *db, struct column *column);
-static void cell_free(pa_inidb_cell *cell);
-static void cell_set_value_internal(pa_inidb_cell *cell, const char *value);
-
-static int parse_assignment(pa_config_parser_state *state) {
- pa_inidb *db;
- const char *end_of_table_name;
- size_t table_name_len;
- char *table_name;
- pa_inidb_table *table;
- const char *row_id;
- pa_inidb_row *row;
- int r;
- void *object;
- struct column *column;
- pa_inidb_cell *cell;
-
- pa_assert(state);
-
- db = state->userdata;
-
- /* FIXME: pa_config_parser should be improved so that it could parse the
- * table name and row id for us in the section header. */
- end_of_table_name = strchr(state->section, ' ');
- if (!end_of_table_name) {
- pa_log("[%s:%u] Failed to parse table name and row id in section \"%s\"", state->filename, state->lineno,
- state->section);
- return -PA_ERR_INVALID;
- }
-
- table_name_len = end_of_table_name - state->section;
- table_name = pa_xstrndup(state->section, table_name_len);
- table = pa_hashmap_get(db->tables, table_name);
- if (!table)
- pa_log("[%s:%u] Unknown table name: \"%s\"", state->filename, state->lineno, table_name);
- pa_xfree(table_name);
- if (!table)
- return -PA_ERR_INVALID;
-
- row_id = end_of_table_name + 1;
- if (!pa_namereg_is_valid_name(row_id)) {
- pa_log("[%s:%u] Invalid row id: \"%s\"", state->filename, state->lineno, row_id);
- return -PA_ERR_INVALID;
- }
-
- /* This is not strictly necessary, but we do this to avoid saving the
- * database when there is no actual change. Without this, the get_object()
- * callback would cause redundant saving whenever creating new objects. */
- if (!(row = pa_hashmap_get(table->rows, row_id)))
- row = table_add_row_internal(table, row_id);
-
- r = table->get_object(db, row_id, &object);
- if (r < 0) {
- pa_log("[%s:%u] Failed to create object %s.", state->filename, state->lineno, row_id);
- return r;
- }
-
- column = pa_hashmap_get(table->columns, state->lvalue);
- if (!column) {
- pa_log("[%s:%u] Unknown column name: \"%s\"", state->filename, state->lineno, state->lvalue);
- return -PA_ERR_INVALID;
- }
-
- /* This is not strictly necessary, but we do this to avoid saving the
- * database when there is no actual change. Without this, the parse()
- * callback would cause redundant saving whenever setting the cell value
- * for the first time. */
- cell = pa_hashmap_get(row->cells, column->name);
- cell_set_value_internal(cell, state->rvalue);
-
- r = column->parse(db, state->rvalue, object);
- if (r < 0) {
- pa_log("[%s:%u] Failed to parse %s value \"%s\".", state->filename, state->lineno, column->name, state->rvalue);
- return r;
- }
-
- return 0;
-}
-
-pa_inidb *pa_inidb_new(pa_core *core, const char *name, void *userdata) {
- pa_inidb *db;
- int r;
-
- pa_assert(core);
- pa_assert(name);
-
- db = pa_xnew0(pa_inidb, 1);
- db->core = core;
- db->name = pa_xstrdup(name);
-
- r = pa_append_to_config_home_dir(name, true, &db->file_path);
- if (r < 0) {
- pa_log("Failed to find the file location for database \"%s\". The database will start empty, and updates will not be "
- "saved on disk.", name);
- db->failed = true;
- }
-
- if (db->file_path)
- db->tmp_file_path = pa_sprintf_malloc("%s.tmp", db->file_path);
-
- db->tables = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
- (pa_free_cb_t) table_free);
- db->userdata = userdata;
-
- return db;
-}
-
-void pa_inidb_free(pa_inidb *db) {
- pa_assert(db);
-
- if (db->time_event) {
- db->core->mainloop->time_free(db->time_event);
- save(db);
- }
-
- if (db->tables)
- pa_hashmap_free(db->tables);
-
- pa_xfree(db->tmp_file_path);
- pa_xfree(db->file_path);
- pa_xfree(db->name);
- pa_xfree(db);
-}
-
-void *pa_inidb_get_userdata(pa_inidb *db) {
- pa_assert(db);
-
- return db->userdata;
-}
-
-pa_inidb_table *pa_inidb_add_table(pa_inidb *db, const char *name, pa_inidb_get_object_cb_t get_object_cb) {
- pa_inidb_table *table;
-
- pa_assert(db);
- pa_assert(name);
- pa_assert(get_object_cb);
-
- table = table_new(db, name, get_object_cb);
- pa_assert_se(pa_hashmap_put(db->tables, table->name, table) >= 0);
-
- return table;
-}
-
-void pa_inidb_load(pa_inidb *db) {
- unsigned n_config_items;
- pa_inidb_table *table;
- void *state;
- pa_config_item *config_items;
- unsigned i;
-
- pa_assert(db);
-
- if (db->failed)
- return;
-
- n_config_items = 0;
- PA_HASHMAP_FOREACH(table, db->tables, state)
- n_config_items += pa_hashmap_size(table->columns);
-
- config_items = pa_xnew0(pa_config_item, n_config_items + 1);
-
- i = 0;
- PA_HASHMAP_FOREACH(table, db->tables, state) {
- struct column *column;
- void *state2;
-
- PA_HASHMAP_FOREACH(column, table->columns, state2) {
- config_items[i].lvalue = column->name;
- config_items[i].parse = parse_assignment;
- i++;
- }
- }
-
- pa_config_parse(db->file_path, NULL, config_items, NULL, db);
- pa_xfree(config_items);
-}
-
-static void save(pa_inidb *db) {
- FILE *f;
- pa_inidb_table *table;
- void *state;
- int r;
-
- pa_assert(db);
-
- if (db->failed)
- return;
-
- f = pa_fopen_cloexec(db->tmp_file_path, "w");
- if (!f) {
- pa_log("pa_fopen_cloexec() failed: %s", pa_cstrerror(errno));
- goto fail;
- }
-
- PA_HASHMAP_FOREACH(table, db->tables, state) {
- pa_inidb_row *row;
- void *state2;
-
- PA_HASHMAP_FOREACH(row, table->rows, state2) {
- size_t len;
- size_t items_written;
- pa_inidb_cell *cell;
- void *state3;
-
- len = strlen(row->header);
- items_written = fwrite(row->header, len, 1, f);
-
- if (items_written != 1) {
- pa_log("fwrite() failed: %s", pa_cstrerror(errno));
- goto fail;
- }
-
- PA_HASHMAP_FOREACH(cell, row->cells, state3) {
- if (!cell->assignment)
- continue;
-
- len = strlen(cell->assignment);
- items_written = fwrite(cell->assignment, len, 1, f);
-
- if (items_written != 1) {
- pa_log("fwrite() failed: %s", pa_cstrerror(errno));
- goto fail;
- }
- }
-
- items_written = fwrite("\n", 1, 1, f);
-
- if (items_written != 1) {
- pa_log("fwrite() failed: %s", pa_cstrerror(errno));
- goto fail;
- }
- }
- }
-
- r = fclose(f);
- f = NULL;
- if (r < 0) {
- pa_log("fclose() failed: %s", pa_cstrerror(errno));
- goto fail;
- }
-
- r = rename(db->tmp_file_path, db->file_path);
- if (r < 0) {
- pa_log("rename() failed: %s", pa_cstrerror(errno));
- goto fail;
- }
-
- pa_log_debug("Database \"%s\" saved.", db->name);
-
- return;
-
-fail:
- if (f)
- fclose(f);
-
- db->failed = true;
- pa_log("Saving database \"%s\" failed, current and future database changes will not be written to the disk.", db->name);
-}
-
-static pa_inidb_table *table_new(pa_inidb *db, const char *name, pa_inidb_get_object_cb_t get_object_cb) {
- pa_inidb_table *table;
-
- pa_assert(db);
- pa_assert(name);
- pa_assert(get_object_cb);
-
- table = pa_xnew0(pa_inidb_table, 1);
- table->db = db;
- table->name = pa_xstrdup(name);
- table->columns = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
- (pa_free_cb_t) column_free);
- table->rows = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
- (pa_free_cb_t) row_free);
- table->get_object = get_object_cb;
-
- return table;
-}
-
-static void table_free(pa_inidb_table *table) {
- pa_assert(table);
-
- if (table->rows)
- pa_hashmap_free(table->rows);
-
- if (table->columns)
- pa_hashmap_free(table->columns);
-
- pa_xfree(table->name);
- pa_xfree(table);
-}
-
-void pa_inidb_table_add_column(pa_inidb_table *table, const char *name, pa_inidb_parse_cb_t parse_cb) {
- struct column *column;
-
- pa_assert(table);
- pa_assert(name);
- pa_assert(parse_cb);
-
- column = column_new(name, parse_cb);
- pa_assert_se(pa_hashmap_put(table->columns, column->name, column) >= 0);
-}
-
-static pa_inidb_row *table_add_row_internal(pa_inidb_table *table, const char *row_id) {
- pa_inidb_row *row;
-
- pa_assert(table);
- pa_assert(row_id);
-
- row = row_new(table, row_id);
- pa_assert_se(pa_hashmap_put(table->rows, row->id, row) >= 0);
-
- return row;
-}
-
-static void time_cb(pa_mainloop_api *api, pa_time_event *event, const struct timeval *tv, void *userdata) {
- pa_inidb *db = userdata;
-
- pa_assert(api);
- pa_assert(db);
-
- api->time_free(event);
- db->time_event = NULL;
-
- save(db);
-}
-
-static void trigger_save(pa_inidb *db) {
- struct timeval tv;
-
- pa_assert(db);
-
- if (db->time_event)
- return;
-
- pa_timeval_rtstore(&tv, pa_rtclock_now() + SAVE_INTERVAL_USEC, true);
- db->time_event = db->core->mainloop->time_new(db->core->mainloop, &tv, time_cb, db);
-}
-
-pa_inidb_row *pa_inidb_table_add_row(pa_inidb_table *table, const char *row_id) {
- pa_inidb_row *row;
-
- pa_assert(table);
- pa_assert(row_id);
-
- row = pa_hashmap_get(table->rows, row_id);
- if (row)
- return row;
-
- row = table_add_row_internal(table, row_id);
- trigger_save(table->db);
-
- return row;
-}
-
-static struct column *column_new(const char *name, pa_inidb_parse_cb_t parse_cb) {
- struct column *column;
-
- pa_assert(name);
- pa_assert(parse_cb);
-
- column = pa_xnew(struct column, 1);
- column->name = pa_xstrdup(name);
- column->parse = parse_cb;
-
- return column;
-}
-
-static void column_free(struct column *column) {
- pa_assert(column);
-
- pa_xfree(column->name);
- pa_xfree(column);
-}
-
-static pa_inidb_row *row_new(pa_inidb_table *table, const char *id) {
- pa_inidb_row *row;
- struct column *column;
- void *state;
-
- pa_assert(table);
- pa_assert(id);
-
- row = pa_xnew0(pa_inidb_row, 1);
- row->id = pa_xstrdup(id);
- row->header = pa_sprintf_malloc("[%s %s]\n", table->name, id);
- row->cells = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
- (pa_free_cb_t) cell_free);
-
- PA_HASHMAP_FOREACH(column, table->columns, state) {
- pa_inidb_cell *cell;
-
- cell = cell_new(table->db, column);
- pa_hashmap_put(row->cells, cell->column->name, cell);
- }
-
- return row;
-}
-
-static void row_free(pa_inidb_row *row) {
- pa_assert(row);
-
- pa_xfree(row->header);
- pa_xfree(row->id);
- pa_xfree(row);
-}
-
-pa_inidb_cell *pa_inidb_row_get_cell(pa_inidb_row *row, const char *column_name) {
- pa_inidb_cell *cell;
-
- pa_assert(row);
- pa_assert(column_name);
-
- pa_assert_se(cell = pa_hashmap_get(row->cells, column_name));
-
- return cell;
-}
-
-static pa_inidb_cell *cell_new(pa_inidb *db, struct column *column) {
- pa_inidb_cell *cell;
-
- pa_assert(db);
- pa_assert(column);
-
- cell = pa_xnew0(pa_inidb_cell, 1);
- cell->db = db;
- cell->column = column;
-
- return cell;
-}
-
-static void cell_free(pa_inidb_cell *cell) {
- pa_assert(cell);
-
- pa_xfree(cell->assignment);
- pa_xfree(cell->value);
- pa_xfree(cell);
-}
-
-static void cell_set_value_internal(pa_inidb_cell *cell, const char *value) {
- pa_assert(cell);
- pa_assert(value);
-
- pa_xfree(cell->value);
- cell->value = pa_xstrdup(value);
-
- pa_xfree(cell->assignment);
- if (value)
- cell->assignment = pa_sprintf_malloc("%s = %s\n", cell->column->name, value);
- else
- cell->assignment = NULL;
-}
-
-void pa_inidb_cell_set_value(pa_inidb_cell *cell, const char *value) {
- pa_assert(cell);
-
- if (pa_safe_streq(value, cell->value))
- return;
-
- cell_set_value_internal(cell, value);
- trigger_save(cell->db);
-}
+++ /dev/null
-#ifndef fooinidbhfoo
-#define fooinidbhfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <pulsecore/core.h>
-
-typedef struct pa_inidb pa_inidb;
-typedef struct pa_inidb_cell pa_inidb_cell;
-typedef struct pa_inidb_row pa_inidb_row;
-typedef struct pa_inidb_table pa_inidb_table;
-
-/* If there's no object with the given name, the implementation is expected to
- * create a new object (or at least try to). */
-typedef int (*pa_inidb_get_object_cb_t)(pa_inidb *db, const char *name, void **_r);
-
-/* The implementation is expected to parse the value, and set the parsed value
- * on the object. */
-typedef int (*pa_inidb_parse_cb_t)(pa_inidb *db, const char *value, void *object);
-
-pa_inidb *pa_inidb_new(pa_core *core, const char *name, void *userdata);
-void pa_inidb_free(pa_inidb *db);
-
-void *pa_inidb_get_userdata(pa_inidb *db);
-pa_inidb_table *pa_inidb_add_table(pa_inidb *db, const char *name, pa_inidb_get_object_cb_t get_object_cb);
-void pa_inidb_load(pa_inidb *db);
-
-void pa_inidb_table_add_column(pa_inidb_table *table, const char *name, pa_inidb_parse_cb_t parse_cb);
-pa_inidb_row *pa_inidb_table_add_row(pa_inidb_table *table, const char *row_id);
-
-pa_inidb_cell *pa_inidb_row_get_cell(pa_inidb_row *row, const char *column_name);
-
-void pa_inidb_cell_set_value(pa_inidb_cell *cell, const char *value);
-
-#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "module-volume-api-symdef.h"
-
-#include <modules/volume-api/audio-group.h>
-#include <modules/volume-api/bvolume.h>
-#include <modules/volume-api/device.h>
-#include <modules/volume-api/sstream.h>
-#include <modules/volume-api/volume-api.h>
-#include <modules/volume-api/volume-api-common.h>
-#include <modules/volume-api/volume-control.h>
-
-#include <pulsecore/core-util.h>
-#include <pulsecore/i18n.h>
-#include <pulsecore/protocol-native.h>
-#include <pulsecore/pstream-util.h>
-
-PA_MODULE_AUTHOR("Tanu Kaskinen");
-PA_MODULE_DESCRIPTION(_("Volume API"));
-PA_MODULE_VERSION(PACKAGE_VERSION);
-PA_MODULE_LOAD_ONCE(true);
-
-struct userdata {
- pa_native_protocol *native_protocol;
- bool extension_installed;
- pa_volume_api *volume_api;
- pa_hook_slot *volume_control_put_slot;
- pa_hook_slot *volume_control_unlink_slot;
- pa_hook_slot *volume_control_description_changed_slot;
- pa_hook_slot *volume_control_volume_changed_slot;
- pa_hook_slot *volume_control_convertible_to_db_changed_slot;
- pa_hook_slot *mute_control_put_slot;
- pa_hook_slot *mute_control_unlink_slot;
- pa_hook_slot *mute_control_description_changed_slot;
- pa_hook_slot *mute_control_mute_changed_slot;
- pa_hook_slot *device_put_slot;
- pa_hook_slot *device_unlink_slot;
- pa_hook_slot *device_description_changed_slot;
- pa_hook_slot *device_volume_control_changed_slot;
- pa_hook_slot *device_mute_control_changed_slot;
- pa_hook_slot *stream_put_slot;
- pa_hook_slot *stream_unlink_slot;
- pa_hook_slot *stream_description_changed_slot;
- pa_hook_slot *stream_proplist_changed_slot;
- pa_hook_slot *stream_volume_control_changed_slot;
- pa_hook_slot *stream_relative_volume_control_changed_slot;
- pa_hook_slot *stream_mute_control_changed_slot;
- pa_hook_slot *audio_group_put_slot;
- pa_hook_slot *audio_group_unlink_slot;
- pa_hook_slot *audio_group_description_changed_slot;
- pa_hook_slot *audio_group_volume_control_changed_slot;
- pa_hook_slot *audio_group_mute_control_changed_slot;
- pa_hook_slot *main_output_volume_control_changed_slot;
- pa_hook_slot *main_input_volume_control_changed_slot;
- pa_hook_slot *main_output_mute_control_changed_slot;
- pa_hook_slot *main_input_mute_control_changed_slot;
- pa_hashmap *connections; /* pa_native_connection -> volume_api_connection */
- pa_hook_slot *native_connection_unlink_slot;
-};
-
-struct volume_api_connection {
- pa_native_connection *native_connection;
- bool dead;
- pa_ext_volume_api_subscription_mask_t subscription_mask;
-};
-
-static struct volume_api_connection *volume_api_connection_new(pa_native_connection *native_connection) {
- struct volume_api_connection *api_connection;
-
- pa_assert(native_connection);
-
- api_connection = pa_xnew0(struct volume_api_connection, 1);
- api_connection->native_connection = native_connection;
-
- return api_connection;
-}
-
-static void volume_api_connection_free(struct volume_api_connection *connection) {
- pa_assert(connection);
-
- pa_xfree(connection);
-}
-
-static void add_connection(struct userdata *u, struct volume_api_connection *connection) {
- pa_assert(u);
- pa_assert(connection);
-
- pa_assert_se(pa_hashmap_put(u->connections, connection->native_connection, connection) >= 0);
-}
-
-static void remove_connection(struct userdata *u, struct volume_api_connection *connection) {
- pa_assert(u);
- pa_assert(connection);
-
- if (!connection->dead) {
- pa_tagstruct *tagstruct;
-
- tagstruct = pa_tagstruct_new(NULL, 0);
- pa_tagstruct_putu32(tagstruct, PA_COMMAND_EXTENSION);
- pa_tagstruct_putu32(tagstruct, (uint32_t) -1);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_DISCONNECT);
- pa_pstream_send_tagstruct(pa_native_connection_get_pstream(connection->native_connection), tagstruct);
- }
-
- pa_assert_se(pa_hashmap_remove_and_free(u->connections, connection->native_connection) >= 0);
-}
-
-static pa_tagstruct *reply_new(uint32_t tag) {
- pa_tagstruct *reply;
-
- reply = pa_tagstruct_new(NULL, 0);
- pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
- pa_tagstruct_putu32(reply, tag);
-
- return reply;
-}
-
-static int command_connect(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- uint32_t version;
- pa_tagstruct *reply;
- struct volume_api_connection *api_connection;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- if (pa_tagstruct_getu32(tagstruct, &version) < 0
- || version < 1
- || !pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a CONNECT command.");
- return -1;
- }
-
- if (pa_hashmap_get(u->connections, native_connection)) {
- pa_log_info("Tried to connect an already connected client.");
- return -1;
- }
-
- reply = reply_new(tag);
- pa_tagstruct_putu32(reply, PA_VOLUME_API_VERSION);
- pa_pstream_send_tagstruct(pa_native_connection_get_pstream(native_connection), reply);
-
- api_connection = volume_api_connection_new(native_connection);
- add_connection(u, api_connection);
-
- return 0;
-}
-
-static int command_disconnect(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- struct volume_api_connection *api_connection;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- if (!pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a DISCONNECT command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("Tried to disconnect an unconnected client.");
- return -1;
- }
-
- remove_connection(u, api_connection);
-
- return 0;
-}
-
-static int command_subscribe(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- uint32_t mask;
- struct volume_api_connection *api_connection;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- if (pa_tagstruct_getu32(tagstruct, &mask) < 0
- || !pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a SUBSCRIBE command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("SUBSCRIBE command received from an unconnected client.");
- return -1;
- }
-
- api_connection->subscription_mask = mask;
-
- return 0;
-}
-
-static void fill_volume_control_info(pa_tagstruct *tagstruct, pa_volume_control *control) {
- unsigned i;
-
- pa_assert(tagstruct);
- pa_assert(control);
-
- pa_tagstruct_putu32(tagstruct, control->index);
- pa_tagstruct_puts(tagstruct, control->name);
- pa_tagstruct_puts(tagstruct, control->description);
- pa_tagstruct_put_proplist(tagstruct, control->proplist);
- pa_tagstruct_put_volume(tagstruct, control->volume.volume);
- pa_tagstruct_put_channel_map(tagstruct, &control->volume.channel_map);
-
- for (i = 0; i < control->volume.channel_map.channels; i++) {
- uint64_t u;
-
- memcpy(&u, &control->volume.balance[i], sizeof(uint64_t));
- pa_tagstruct_putu64(tagstruct, u);
- }
-
- pa_tagstruct_put_boolean(tagstruct, control->convertible_to_dB);
-}
-
-static int command_get_server_info(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- struct volume_api_connection *api_connection;
- pa_tagstruct *reply;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- if (!pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a GET_SERVER_INFO command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("GET_SERVER_INFO command received from an unconnected client.");
- return -1;
- }
-
- reply = reply_new(tag);
- pa_tagstruct_putu32(reply, u->volume_api->main_output_volume_control
- ? u->volume_api->main_output_volume_control->index
- : PA_INVALID_INDEX);
- pa_tagstruct_putu32(reply, u->volume_api->main_input_volume_control
- ? u->volume_api->main_input_volume_control->index
- : PA_INVALID_INDEX);
- pa_tagstruct_putu32(reply, u->volume_api->main_output_mute_control
- ? u->volume_api->main_output_mute_control->index
- : PA_INVALID_INDEX);
- pa_tagstruct_putu32(reply, u->volume_api->main_input_mute_control
- ? u->volume_api->main_input_mute_control->index
- : PA_INVALID_INDEX);
- pa_pstream_send_tagstruct(pa_native_connection_get_pstream(native_connection), reply);
-
- return 0;
-}
-
-static int command_get_volume_control_info(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- pa_pstream *pstream;
- uint32_t idx;
- const char *name;
- struct volume_api_connection *api_connection;
- pa_volume_control *control = NULL;
- pa_tagstruct *reply;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- pstream = pa_native_connection_get_pstream(native_connection);
-
- if (pa_tagstruct_getu32(tagstruct, &idx) < 0
- || pa_tagstruct_gets(tagstruct, &name)
- || (idx == PA_INVALID_INDEX && !name)
- || (idx != PA_INVALID_INDEX && name)
- || (name && !*name)
- || !pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a GET_VOLUME_CONTROL_INFO command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("GET_VOLUME_CONTROL_INFO command received from an unconnected client.");
- return -1;
- }
-
- if (name) {
- control = pa_hashmap_get(u->volume_api->volume_controls, name);
-
- if (!control)
- pa_atou(name, &idx);
- }
-
- if (idx != PA_INVALID_INDEX)
- control = pa_volume_api_get_volume_control_by_index(u->volume_api, idx);
-
- if (!control) {
- pa_log_info("Tried to get volume control info for a non-existing volume control.");
- pa_pstream_send_error(pstream, tag, PA_ERR_NOENTITY);
- return 0;
- }
-
- reply = reply_new(tag);
- fill_volume_control_info(reply, control);
- pa_pstream_send_tagstruct(pstream, reply);
-
- return 0;
-}
-
-static int command_get_volume_control_info_list(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- struct volume_api_connection *api_connection;
- pa_tagstruct *reply;
- pa_volume_control *control;
- void *state;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- if (!pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a GET_VOLUME_CONTROL_INFO_LIST command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("GET_VOLUME_CONTROL_INFO_LIST command received from an unconnected client.");
- return -1;
- }
-
- reply = reply_new(tag);
-
- PA_HASHMAP_FOREACH(control, u->volume_api->volume_controls, state)
- fill_volume_control_info(reply, control);
-
- pa_pstream_send_tagstruct(pa_native_connection_get_pstream(native_connection), reply);
-
- return 0;
-}
-
-static int command_set_volume_control_volume(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- pa_pstream *pstream;
- uint32_t idx;
- const char *name;
- pa_bvolume bvolume;
- bool set_volume;
- bool set_balance;
- struct volume_api_connection *api_connection;
- pa_volume_control *control = NULL;
- int r;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- pstream = pa_native_connection_get_pstream(native_connection);
-
- if (pa_tagstruct_getu32(tagstruct, &idx) < 0
- || pa_tagstruct_gets(tagstruct, &name) < 0
- || (idx == PA_INVALID_INDEX && !name)
- || (idx != PA_INVALID_INDEX && name)
- || (name && !*name)
- || pa_tagstruct_get_volume(tagstruct, &bvolume.volume) < 0
- || pa_tagstruct_get_channel_map(tagstruct, &bvolume.channel_map) < 0)
- goto fail_parse;
-
- set_volume = PA_VOLUME_IS_VALID(bvolume.volume);
- set_balance = pa_channel_map_valid(&bvolume.channel_map);
-
- if (set_balance) {
- unsigned i;
-
- for (i = 0; i < bvolume.channel_map.channels; i++) {
- uint64_t balance;
-
- if (pa_tagstruct_getu64(tagstruct, &balance) < 0)
- goto fail_parse;
-
- memcpy(&bvolume.balance[i], &balance, sizeof(double));
-
- if (!pa_balance_valid(bvolume.balance[i]))
- goto fail_parse;
- }
- }
-
- if (!pa_tagstruct_eof(tagstruct))
- goto fail_parse;
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("SET_VOLUME_CONTROL_VOLUME received from an unconnected client.");
- return -1;
- }
-
- if (name) {
- control = pa_hashmap_get(u->volume_api->volume_controls, name);
-
- if (!control)
- pa_atou(name, &idx);
- }
-
- if (idx != PA_INVALID_INDEX)
- control = pa_volume_api_get_volume_control_by_index(u->volume_api, idx);
-
- if (!control) {
- pa_log_info("Tried to set volume of a non-existing volume control.");
- pa_pstream_send_error(pstream, tag, PA_ERR_NOENTITY);
- return 0;
- }
-
- r = pa_volume_control_set_volume(control, &bvolume, set_volume, set_balance);
- if (r < 0) {
- pa_pstream_send_error(pstream, tag, -r);
- return 0;
- }
-
- pa_pstream_send_simple_ack(pstream, tag);
-
- return 0;
-
-fail_parse:
- pa_log_info("Failed to parse the parameters of a SET_VOLUME_CONTROL_VOLUME command.");
-
- return -1;
-}
-
-static void fill_mute_control_info(pa_tagstruct *tagstruct, pa_mute_control *control) {
- pa_assert(tagstruct);
- pa_assert(control);
-
- pa_tagstruct_putu32(tagstruct, control->index);
- pa_tagstruct_puts(tagstruct, control->name);
- pa_tagstruct_puts(tagstruct, control->description);
- pa_tagstruct_put_proplist(tagstruct, control->proplist);
- pa_tagstruct_put_boolean(tagstruct, control->mute);
-}
-
-static int command_get_mute_control_info(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- pa_pstream *pstream;
- uint32_t idx;
- const char *name;
- struct volume_api_connection *api_connection;
- pa_mute_control *control = NULL;
- pa_tagstruct *reply;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- pstream = pa_native_connection_get_pstream(native_connection);
-
- if (pa_tagstruct_getu32(tagstruct, &idx) < 0
- || pa_tagstruct_gets(tagstruct, &name)
- || (idx == PA_INVALID_INDEX && !name)
- || (idx != PA_INVALID_INDEX && name)
- || (name && !*name)
- || !pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a GET_MUTE_CONTROL_INFO command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("GET_MUTE_CONTROL_INFO command received from an unconnected client.");
- return -1;
- }
-
- if (name) {
- control = pa_hashmap_get(u->volume_api->mute_controls, name);
-
- if (!control)
- pa_atou(name, &idx);
- }
-
- if (idx != PA_INVALID_INDEX)
- control = pa_volume_api_get_mute_control_by_index(u->volume_api, idx);
-
- if (!control) {
- pa_log_info("Tried to get mute control info for a non-existing mute control.");
- pa_pstream_send_error(pstream, tag, PA_ERR_NOENTITY);
- return 0;
- }
-
- reply = reply_new(tag);
- fill_mute_control_info(reply, control);
- pa_pstream_send_tagstruct(pstream, reply);
-
- return 0;
-}
-
-static int command_get_mute_control_info_list(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- struct volume_api_connection *api_connection;
- pa_tagstruct *reply;
- pa_mute_control *control;
- void *state;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- if (!pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a GET_MUTE_CONTROL_INFO_LIST command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("GET_MUTE_CONTROL_INFO_LIST command received from an unconnected client.");
- return -1;
- }
-
- reply = reply_new(tag);
-
- PA_HASHMAP_FOREACH(control, u->volume_api->mute_controls, state)
- fill_mute_control_info(reply, control);
-
- pa_pstream_send_tagstruct(pa_native_connection_get_pstream(native_connection), reply);
-
- return 0;
-}
-
-static int command_set_mute_control_mute(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- pa_pstream *pstream;
- uint32_t idx;
- const char *name;
- bool mute;
- struct volume_api_connection *api_connection;
- pa_mute_control *control = NULL;
- int r;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- pstream = pa_native_connection_get_pstream(native_connection);
-
- if (pa_tagstruct_getu32(tagstruct, &idx) < 0
- || pa_tagstruct_gets(tagstruct, &name) < 0
- || (idx == PA_INVALID_INDEX && !name)
- || (idx != PA_INVALID_INDEX && name)
- || (name && !*name)
- || pa_tagstruct_get_boolean(tagstruct, &mute) < 0
- || !pa_tagstruct_eof(tagstruct))
- goto fail_parse;
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("SET_MUTE_CONTROL_MUTE received from an unconnected client.");
- return -1;
- }
-
- if (name) {
- control = pa_hashmap_get(u->volume_api->mute_controls, name);
-
- if (!control)
- pa_atou(name, &idx);
- }
-
- if (idx != PA_INVALID_INDEX)
- control = pa_volume_api_get_mute_control_by_index(u->volume_api, idx);
-
- if (!control) {
- pa_log_info("Tried to set mute of a non-existing mute control.");
- pa_pstream_send_error(pstream, tag, PA_ERR_NOENTITY);
- return 0;
- }
-
- r = pa_mute_control_set_mute(control, mute);
- if (r < 0) {
- pa_pstream_send_error(pstream, tag, -r);
- return 0;
- }
-
- pa_pstream_send_simple_ack(pstream, tag);
-
- return 0;
-
-fail_parse:
- pa_log_info("Failed to parse the parameters of a SET_MUTE_CONTROL_MUTE command.");
-
- return -1;
-}
-
-static void fill_device_info(pa_tagstruct *tagstruct, pa_device *device) {
- unsigned i;
-
- pa_assert(tagstruct);
- pa_assert(device);
-
- pa_tagstruct_putu32(tagstruct, device->index);
- pa_tagstruct_puts(tagstruct, device->name);
- pa_tagstruct_puts(tagstruct, device->description);
- pa_tagstruct_putu8(tagstruct, device->direction);
- pa_tagstruct_putu32(tagstruct, pa_dynarray_size(device->device_types));
-
- for (i = 0; i < pa_dynarray_size(device->device_types); i++)
- pa_tagstruct_puts(tagstruct, pa_dynarray_get(device->device_types, i));
-
- pa_tagstruct_put_proplist(tagstruct, device->proplist);
- pa_tagstruct_putu32(tagstruct, device->volume_control ? device->volume_control->index : PA_INVALID_INDEX);
- pa_tagstruct_putu32(tagstruct, device->mute_control ? device->mute_control->index : PA_INVALID_INDEX);
-}
-
-static int command_get_device_info(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- pa_pstream *pstream;
- uint32_t idx;
- const char *name;
- struct volume_api_connection *api_connection;
- pa_device *device = NULL;
- pa_tagstruct *reply;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- pstream = pa_native_connection_get_pstream(native_connection);
-
- if (pa_tagstruct_getu32(tagstruct, &idx) < 0
- || pa_tagstruct_gets(tagstruct, &name)
- || (idx == PA_INVALID_INDEX && !name)
- || (idx != PA_INVALID_INDEX && name)
- || (name && !*name)
- || !pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a GET_DEVICE_INFO command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("GET_DEVICE_INFO command received from an unconnected client.");
- return -1;
- }
-
- if (name) {
- device = pa_hashmap_get(u->volume_api->devices, name);
-
- if (!device)
- pa_atou(name, &idx);
- }
-
- if (idx != PA_INVALID_INDEX)
- device = pa_volume_api_get_device_by_index(u->volume_api, idx);
-
- if (!device) {
- pa_log_info("Tried to get device info for a non-existing device.");
- pa_pstream_send_error(pstream, tag, PA_ERR_NOENTITY);
- return 0;
- }
-
- reply = reply_new(tag);
- fill_device_info(reply, device);
- pa_pstream_send_tagstruct(pstream, reply);
-
- return 0;
-}
-
-static int command_get_device_info_list(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- struct volume_api_connection *api_connection;
- pa_tagstruct *reply;
- pa_device *device;
- void *state;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- if (!pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a GET_DEVICE_INFO_LIST command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("GET_DEVICE_INFO_LIST command received from an unconnected client.");
- return -1;
- }
-
- reply = reply_new(tag);
-
- PA_HASHMAP_FOREACH(device, u->volume_api->devices, state)
- fill_device_info(reply, device);
-
- pa_pstream_send_tagstruct(pa_native_connection_get_pstream(native_connection), reply);
-
- return 0;
-}
-
-static void fill_stream_info(pa_tagstruct *tagstruct, pas_stream *stream) {
- pa_assert(tagstruct);
- pa_assert(stream);
-
- pa_tagstruct_putu32(tagstruct, stream->index);
- pa_tagstruct_puts(tagstruct, stream->name);
- pa_tagstruct_puts(tagstruct, stream->description);
- pa_tagstruct_putu8(tagstruct, stream->direction);
- pa_tagstruct_put_proplist(tagstruct, stream->proplist);
- pa_tagstruct_putu32(tagstruct, stream->volume_control ? stream->volume_control->index : PA_INVALID_INDEX);
- pa_tagstruct_putu32(tagstruct, stream->mute_control ? stream->mute_control->index : PA_INVALID_INDEX);
-}
-
-static int command_get_stream_info(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- pa_pstream *pstream;
- uint32_t idx;
- const char *name;
- struct volume_api_connection *api_connection;
- pas_stream *stream = NULL;
- pa_tagstruct *reply;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- pstream = pa_native_connection_get_pstream(native_connection);
-
- if (pa_tagstruct_getu32(tagstruct, &idx) < 0
- || pa_tagstruct_gets(tagstruct, &name)
- || (idx == PA_INVALID_INDEX && !name)
- || (idx != PA_INVALID_INDEX && name)
- || (name && !*name)
- || !pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a GET_STREAM_INFO command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("GET_STREAM_INFO command received from an unconnected client.");
- return -1;
- }
-
- if (name) {
- stream = pa_hashmap_get(u->volume_api->streams, name);
-
- if (!stream)
- pa_atou(name, &idx);
- }
-
- if (idx != PA_INVALID_INDEX)
- stream = pa_volume_api_get_stream_by_index(u->volume_api, idx);
-
- if (!stream) {
- pa_log_info("Tried to get stream info for a non-existing stream.");
- pa_pstream_send_error(pstream, tag, PA_ERR_NOENTITY);
- return 0;
- }
-
- reply = reply_new(tag);
- fill_stream_info(reply, stream);
- pa_pstream_send_tagstruct(pstream, reply);
-
- return 0;
-}
-
-static int command_get_stream_info_list(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- struct volume_api_connection *api_connection;
- pa_tagstruct *reply;
- pas_stream *stream;
- void *state;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- if (!pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a GET_STREAM_INFO_LIST command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("GET_STREAM_INFO_LIST command received from an unconnected client.");
- return -1;
- }
-
- reply = reply_new(tag);
-
- PA_HASHMAP_FOREACH(stream, u->volume_api->streams, state)
- fill_stream_info(reply, stream);
-
- pa_pstream_send_tagstruct(pa_native_connection_get_pstream(native_connection), reply);
-
- return 0;
-}
-
-static void fill_audio_group_info(pa_tagstruct *tagstruct, pa_audio_group *group) {
- pa_assert(tagstruct);
- pa_assert(group);
-
- pa_tagstruct_putu32(tagstruct, group->index);
- pa_tagstruct_puts(tagstruct, group->name);
- pa_tagstruct_puts(tagstruct, group->description);
- pa_tagstruct_put_proplist(tagstruct, group->proplist);
- pa_tagstruct_putu32(tagstruct, group->volume_control ? group->volume_control->index : PA_INVALID_INDEX);
- pa_tagstruct_putu32(tagstruct, group->mute_control ? group->mute_control->index : PA_INVALID_INDEX);
-}
-
-static int command_get_audio_group_info(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- pa_pstream *pstream;
- uint32_t idx;
- const char *name;
- struct volume_api_connection *api_connection;
- pa_audio_group *group = NULL;
- pa_tagstruct *reply;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- pstream = pa_native_connection_get_pstream(native_connection);
-
- if (pa_tagstruct_getu32(tagstruct, &idx) < 0
- || pa_tagstruct_gets(tagstruct, &name)
- || (idx == PA_INVALID_INDEX && !name)
- || (idx != PA_INVALID_INDEX && name)
- || (name && !*name)
- || !pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a GET_AUDIO_GROUP_INFO command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("GET_AUDIO_GROUP_INFO command received from an unconnected client.");
- return -1;
- }
-
- if (name) {
- group = pa_hashmap_get(u->volume_api->audio_groups, name);
-
- if (!group)
- pa_atou(name, &idx);
- }
-
- if (idx != PA_INVALID_INDEX)
- group = pa_volume_api_get_audio_group_by_index(u->volume_api, idx);
-
- if (!group) {
- pa_log_info("Tried to get audio group info for a non-existing audio group.");
- pa_pstream_send_error(pstream, tag, PA_ERR_NOENTITY);
- return 0;
- }
-
- reply = reply_new(tag);
- fill_audio_group_info(reply, group);
- pa_pstream_send_tagstruct(pstream, reply);
-
- return 0;
-}
-
-static int command_get_audio_group_info_list(struct userdata *u, pa_native_connection *native_connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- struct volume_api_connection *api_connection;
- pa_tagstruct *reply;
- pa_audio_group *group;
- void *state;
-
- pa_assert(u);
- pa_assert(native_connection);
- pa_assert(tagstruct);
-
- if (!pa_tagstruct_eof(tagstruct)) {
- pa_log_info("Failed to parse the parameters of a GET_AUDIO_GROUP_INFO_LIST command.");
- return -1;
- }
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection) {
- pa_log_info("GET_AUDIO_GROUP_INFO_LIST command received from an unconnected client.");
- return -1;
- }
-
- reply = reply_new(tag);
-
- PA_HASHMAP_FOREACH(group, u->volume_api->audio_groups, state)
- fill_audio_group_info(reply, group);
-
- pa_pstream_send_tagstruct(pa_native_connection_get_pstream(native_connection), reply);
-
- return 0;
-}
-
-static int extension_cb(pa_native_protocol *protocol, pa_module *module, pa_native_connection *connection, uint32_t tag,
- pa_tagstruct *tagstruct) {
- struct userdata *u;
- uint32_t command;
-
- pa_assert(protocol);
- pa_assert(module);
- pa_assert(connection);
- pa_assert(tagstruct);
-
- u = module->userdata;
-
- if (pa_tagstruct_getu32(tagstruct, &command) < 0)
- return -1;
-
- switch (command) {
- case PA_VOLUME_API_COMMAND_CONNECT:
- return command_connect(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_DISCONNECT:
- return command_disconnect(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_SUBSCRIBE:
- return command_subscribe(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_GET_SERVER_INFO:
- return command_get_server_info(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_GET_VOLUME_CONTROL_INFO:
- return command_get_volume_control_info(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_GET_VOLUME_CONTROL_INFO_LIST:
- return command_get_volume_control_info_list(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_SET_VOLUME_CONTROL_VOLUME:
- return command_set_volume_control_volume(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_GET_MUTE_CONTROL_INFO:
- return command_get_mute_control_info(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_GET_MUTE_CONTROL_INFO_LIST:
- return command_get_mute_control_info_list(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_SET_MUTE_CONTROL_MUTE:
- return command_set_mute_control_mute(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_GET_DEVICE_INFO:
- return command_get_device_info(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_GET_DEVICE_INFO_LIST:
- return command_get_device_info_list(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_GET_STREAM_INFO:
- return command_get_stream_info(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_GET_STREAM_INFO_LIST:
- return command_get_stream_info_list(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_GET_AUDIO_GROUP_INFO:
- return command_get_audio_group_info(u, connection, tag, tagstruct);
-
- case PA_VOLUME_API_COMMAND_GET_AUDIO_GROUP_INFO_LIST:
- return command_get_audio_group_info_list(u, connection, tag, tagstruct);
-
- default:
- pa_log_info("Received unrecognized command: %u", command);
- return -1;
- }
-}
-
-static void send_subscribe_event(struct userdata *u, pa_ext_volume_api_subscription_event_type_t event_type,
- uint32_t idx) {
- pa_ext_volume_api_subscription_event_type_t facility;
- struct volume_api_connection *connection;
- void *state;
-
- pa_assert(u);
-
- facility = event_type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
-
- PA_HASHMAP_FOREACH(connection, u->connections, state) {
- pa_tagstruct *tagstruct;
-
- if (!(connection->subscription_mask & (1 << facility)))
- continue;
-
- tagstruct = pa_tagstruct_new(NULL, 0);
- pa_tagstruct_putu32(tagstruct, PA_COMMAND_EXTENSION);
- pa_tagstruct_putu32(tagstruct, (uint32_t) -1);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_SUBSCRIBE_EVENT);
- pa_tagstruct_putu32(tagstruct, event_type);
- pa_tagstruct_putu32(tagstruct, idx);
- pa_pstream_send_tagstruct(pa_native_connection_get_pstream(connection->native_connection), tagstruct);
- }
-}
-
-static pa_hook_result_t volume_control_put_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_volume_control *control = call_data;
-
- pa_assert(u);
- pa_assert(control);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_VOLUME_CONTROL | PA_SUBSCRIPTION_EVENT_NEW,
- control->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t volume_control_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_volume_control *control = call_data;
-
- pa_assert(u);
- pa_assert(control);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_VOLUME_CONTROL | PA_SUBSCRIPTION_EVENT_REMOVE,
- control->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t volume_control_event_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_volume_control *control = call_data;
-
- pa_assert(u);
- pa_assert(control);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_VOLUME_CONTROL | PA_SUBSCRIPTION_EVENT_CHANGE,
- control->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t mute_control_put_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_mute_control *control = call_data;
-
- pa_assert(u);
- pa_assert(control);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_MUTE_CONTROL | PA_SUBSCRIPTION_EVENT_NEW,
- control->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t mute_control_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_mute_control *control = call_data;
-
- pa_assert(u);
- pa_assert(control);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_MUTE_CONTROL | PA_SUBSCRIPTION_EVENT_REMOVE,
- control->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t mute_control_event_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_mute_control *control = call_data;
-
- pa_assert(u);
- pa_assert(control);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_MUTE_CONTROL | PA_SUBSCRIPTION_EVENT_CHANGE,
- control->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t device_put_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_device *device = call_data;
-
- pa_assert(u);
- pa_assert(device);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_DEVICE | PA_SUBSCRIPTION_EVENT_NEW, device->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t device_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_device *device = call_data;
-
- pa_assert(u);
- pa_assert(device);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_DEVICE | PA_SUBSCRIPTION_EVENT_REMOVE, device->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t device_event_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_device *device = call_data;
-
- pa_assert(u);
- pa_assert(device);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_DEVICE | PA_SUBSCRIPTION_EVENT_CHANGE, device->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t stream_put_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pas_stream *stream = call_data;
-
- pa_assert(u);
- pa_assert(stream);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_STREAM | PA_SUBSCRIPTION_EVENT_NEW, stream->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t stream_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pas_stream *stream = call_data;
-
- pa_assert(u);
- pa_assert(stream);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_STREAM | PA_SUBSCRIPTION_EVENT_REMOVE, stream->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t stream_event_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pas_stream *stream = call_data;
-
- pa_assert(u);
- pa_assert(stream);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_STREAM | PA_SUBSCRIPTION_EVENT_CHANGE, stream->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t audio_group_put_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_audio_group *group = call_data;
-
- pa_assert(u);
- pa_assert(group);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_AUDIO_GROUP | PA_SUBSCRIPTION_EVENT_NEW, group->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t audio_group_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_audio_group *group = call_data;
-
- pa_assert(u);
- pa_assert(group);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_AUDIO_GROUP | PA_SUBSCRIPTION_EVENT_REMOVE,
- group->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t audio_group_event_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
- pa_audio_group *group = call_data;
-
- pa_assert(u);
- pa_assert(group);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_AUDIO_GROUP | PA_SUBSCRIPTION_EVENT_CHANGE,
- group->index);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t server_event_cb(void *hook_data, void *call_data, void *userdata) {
- struct userdata *u = userdata;
-
- pa_assert(u);
-
- send_subscribe_event(u, PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE,
- PA_INVALID_INDEX);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t native_connection_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- pa_native_connection *native_connection = call_data;
- struct userdata *u = userdata;
- struct volume_api_connection *api_connection;
-
- pa_assert(native_connection);
- pa_assert(u);
-
- api_connection = pa_hashmap_get(u->connections, native_connection);
- if (!api_connection)
- return PA_HOOK_OK;
-
- api_connection->dead = true;
- remove_connection(u, api_connection);
-
- return PA_HOOK_OK;
-}
-
-int pa__init(pa_module *module) {
- struct userdata *u;
-
- pa_assert(module);
-
- u = module->userdata = pa_xnew0(struct userdata, 1);
- u->native_protocol = pa_native_protocol_get(module->core);
- pa_native_protocol_install_ext(u->native_protocol, module, extension_cb);
- u->extension_installed = true;
- u->volume_api = pa_volume_api_get(module->core);
- u->volume_control_put_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_PUT],
- PA_HOOK_NORMAL, volume_control_put_cb, u);
- u->volume_control_unlink_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK], PA_HOOK_NORMAL,
- volume_control_unlink_cb, u);
- u->volume_control_description_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_DESCRIPTION_CHANGED],
- PA_HOOK_NORMAL, volume_control_event_cb, u);
- u->volume_control_volume_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_VOLUME_CHANGED],
- PA_HOOK_NORMAL, volume_control_event_cb, u);
- u->volume_control_convertible_to_db_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_CONVERTIBLE_TO_DB_CHANGED], PA_HOOK_NORMAL,
- volume_control_event_cb, u);
- u->mute_control_put_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_PUT],
- PA_HOOK_NORMAL, mute_control_put_cb, u);
- u->mute_control_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK],
- PA_HOOK_NORMAL, mute_control_unlink_cb, u);
- u->mute_control_description_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_DESCRIPTION_CHANGED],
- PA_HOOK_NORMAL, mute_control_event_cb, u);
- u->mute_control_mute_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_MUTE_CHANGED], PA_HOOK_NORMAL,
- mute_control_event_cb, u);
- u->device_put_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_PUT], PA_HOOK_NORMAL,
- device_put_cb, u);
- u->device_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_UNLINK],
- PA_HOOK_NORMAL, device_unlink_cb, u);
- u->device_description_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_DESCRIPTION_CHANGED], PA_HOOK_NORMAL,
- device_event_cb, u);
- u->device_volume_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_VOLUME_CONTROL_CHANGED],
- PA_HOOK_NORMAL, device_event_cb, u);
- u->device_mute_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_MUTE_CONTROL_CHANGED], PA_HOOK_NORMAL,
- device_event_cb, u);
- u->stream_put_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_PUT], PA_HOOK_NORMAL,
- stream_put_cb, u);
- u->stream_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_UNLINK],
- PA_HOOK_NORMAL, stream_unlink_cb, u);
- u->stream_description_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_DESCRIPTION_CHANGED], PA_HOOK_NORMAL,
- stream_event_cb, u);
- u->stream_proplist_changed_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_PROPLIST_CHANGED],
- PA_HOOK_NORMAL, stream_event_cb, u);
- u->stream_volume_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_VOLUME_CONTROL_CHANGED],
- PA_HOOK_NORMAL, stream_event_cb, u);
- u->stream_relative_volume_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_RELATIVE_VOLUME_CONTROL_CHANGED],
- PA_HOOK_NORMAL, stream_event_cb, u);
- u->stream_mute_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_MUTE_CONTROL_CHANGED], PA_HOOK_NORMAL,
- stream_event_cb, u);
- u->audio_group_put_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_PUT],
- PA_HOOK_NORMAL, audio_group_put_cb, u);
- u->audio_group_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK],
- PA_HOOK_NORMAL, audio_group_unlink_cb, u);
- u->audio_group_description_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_DESCRIPTION_CHANGED], PA_HOOK_NORMAL,
- audio_group_event_cb, u);
- u->audio_group_volume_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_VOLUME_CONTROL_CHANGED],
- PA_HOOK_NORMAL, audio_group_event_cb, u);
- u->audio_group_mute_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_MUTE_CONTROL_CHANGED],
- PA_HOOK_NORMAL, audio_group_event_cb, u);
- u->main_output_volume_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED],
- PA_HOOK_NORMAL, server_event_cb, u);
- u->main_input_volume_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MAIN_INPUT_VOLUME_CONTROL_CHANGED],
- PA_HOOK_NORMAL, server_event_cb, u);
- u->main_output_mute_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MAIN_OUTPUT_MUTE_CONTROL_CHANGED],
- PA_HOOK_NORMAL, server_event_cb, u);
- u->main_input_mute_control_changed_slot =
- pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MAIN_INPUT_MUTE_CONTROL_CHANGED],
- PA_HOOK_NORMAL, server_event_cb, u);
- u->connections = pa_hashmap_new_full(NULL, NULL, NULL, (pa_free_cb_t) volume_api_connection_free);
- u->native_connection_unlink_slot =
- pa_hook_connect(&pa_native_protocol_hooks(u->native_protocol)[PA_NATIVE_HOOK_CONNECTION_UNLINK], PA_HOOK_NORMAL,
- native_connection_unlink_cb, u);
-
- return 0;
-}
-
-void pa__done(pa_module *module) {
- struct userdata *u;
-
- pa_assert(module);
-
- u = module->userdata;
- if (!u)
- return;
-
- if (u->native_connection_unlink_slot)
- pa_hook_slot_free(u->native_connection_unlink_slot);
-
- if (u->connections) {
- struct volume_api_connection *connection;
-
- while ((connection = pa_hashmap_first(u->connections)))
- remove_connection(u, connection);
-
- pa_hashmap_free(u->connections);
- }
-
- if (u->main_input_mute_control_changed_slot)
- pa_hook_slot_free(u->main_input_mute_control_changed_slot);
-
- if (u->main_output_mute_control_changed_slot)
- pa_hook_slot_free(u->main_output_mute_control_changed_slot);
-
- if (u->main_input_volume_control_changed_slot)
- pa_hook_slot_free(u->main_input_volume_control_changed_slot);
-
- if (u->main_output_volume_control_changed_slot)
- pa_hook_slot_free(u->main_output_volume_control_changed_slot);
-
- if (u->audio_group_mute_control_changed_slot)
- pa_hook_slot_free(u->audio_group_mute_control_changed_slot);
-
- if (u->audio_group_volume_control_changed_slot)
- pa_hook_slot_free(u->audio_group_volume_control_changed_slot);
-
- if (u->audio_group_description_changed_slot)
- pa_hook_slot_free(u->audio_group_description_changed_slot);
-
- if (u->audio_group_unlink_slot)
- pa_hook_slot_free(u->audio_group_unlink_slot);
-
- if (u->audio_group_put_slot)
- pa_hook_slot_free(u->audio_group_put_slot);
-
- if (u->stream_mute_control_changed_slot)
- pa_hook_slot_free(u->stream_mute_control_changed_slot);
-
- if (u->stream_relative_volume_control_changed_slot)
- pa_hook_slot_free(u->stream_relative_volume_control_changed_slot);
-
- if (u->stream_volume_control_changed_slot)
- pa_hook_slot_free(u->stream_volume_control_changed_slot);
-
- if (u->stream_proplist_changed_slot)
- pa_hook_slot_free(u->stream_proplist_changed_slot);
-
- if (u->stream_description_changed_slot)
- pa_hook_slot_free(u->stream_description_changed_slot);
-
- if (u->stream_unlink_slot)
- pa_hook_slot_free(u->stream_unlink_slot);
-
- if (u->stream_put_slot)
- pa_hook_slot_free(u->stream_put_slot);
-
- if (u->device_mute_control_changed_slot)
- pa_hook_slot_free(u->device_mute_control_changed_slot);
-
- if (u->device_volume_control_changed_slot)
- pa_hook_slot_free(u->device_volume_control_changed_slot);
-
- if (u->device_description_changed_slot)
- pa_hook_slot_free(u->device_description_changed_slot);
-
- if (u->device_unlink_slot)
- pa_hook_slot_free(u->device_unlink_slot);
-
- if (u->device_put_slot)
- pa_hook_slot_free(u->device_put_slot);
-
- if (u->mute_control_mute_changed_slot)
- pa_hook_slot_free(u->mute_control_mute_changed_slot);
-
- if (u->mute_control_description_changed_slot)
- pa_hook_slot_free(u->mute_control_description_changed_slot);
-
- if (u->mute_control_unlink_slot)
- pa_hook_slot_free(u->mute_control_unlink_slot);
-
- if (u->mute_control_put_slot)
- pa_hook_slot_free(u->mute_control_put_slot);
-
- if (u->volume_control_convertible_to_db_changed_slot)
- pa_hook_slot_free(u->volume_control_convertible_to_db_changed_slot);
-
- if (u->volume_control_volume_changed_slot)
- pa_hook_slot_free(u->volume_control_volume_changed_slot);
-
- if (u->volume_control_description_changed_slot)
- pa_hook_slot_free(u->volume_control_description_changed_slot);
-
- if (u->volume_control_unlink_slot)
- pa_hook_slot_free(u->volume_control_unlink_slot);
-
- if (u->volume_control_put_slot)
- pa_hook_slot_free(u->volume_control_put_slot);
-
- if (u->volume_api)
- pa_volume_api_unref(u->volume_api);
-
- if (u->extension_installed)
- pa_native_protocol_remove_ext(u->native_protocol, module);
-
- if (u->native_protocol)
- pa_native_protocol_unref(u->native_protocol);
-
- pa_xfree(u);
-}
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "mute-control.h"
-
-#include <modules/volume-api/audio-group.h>
-#include <modules/volume-api/device.h>
-#include <modules/volume-api/sstream.h>
-
-#include <pulsecore/core-util.h>
-
-int pa_mute_control_new(pa_volume_api *api, const char *name, bool persistent, pa_mute_control **_r) {
- pa_mute_control *control = NULL;
- int r;
-
- pa_assert(api);
- pa_assert(name);
- pa_assert(_r);
-
- control = pa_xnew0(pa_mute_control, 1);
- control->volume_api = api;
- control->index = pa_volume_api_allocate_mute_control_index(api);
-
- r = pa_volume_api_register_name(api, name, false, &control->name);
- if (r < 0)
- goto fail;
-
- control->description = pa_xstrdup(control->name);
- control->proplist = pa_proplist_new();
- control->present = !persistent;
- control->persistent = persistent;
- control->purpose = PA_MUTE_CONTROL_PURPOSE_OTHER;
- control->devices = pa_hashmap_new(NULL, NULL);
- control->default_for_devices = pa_hashmap_new(NULL, NULL);
-
- if (persistent) {
- pa_inidb_row *row;
-
- row = pa_inidb_table_add_row(api->control_db.mute_controls, control->name);
- control->db_cells.description = pa_inidb_row_get_cell(row, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_DESCRIPTION);
- control->db_cells.mute = pa_inidb_row_get_cell(row, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_MUTE);
- }
-
- *_r = control;
- return 0;
-
-fail:
- if (control)
- pa_mute_control_free(control);
-
- return r;
-}
-
-void pa_mute_control_put(pa_mute_control *control) {
- const char *prop_key;
- void *state = NULL;
-
- pa_assert(control);
- pa_assert(control->set_mute || !control->present);
-
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_IMPLEMENTATION_INITIALIZED], control);
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_SET_INITIAL_MUTE], control);
-
- if (control->set_mute) {
- control->set_mute_in_progress = true;
- control->set_mute(control, control->mute);
- control->set_mute_in_progress = false;
- }
-
- pa_volume_api_add_mute_control(control->volume_api, control);
- control->linked = true;
-
- pa_log_debug("Created mute control #%u.", control->index);
- pa_log_debug(" Name: %s", control->name);
- pa_log_debug(" Description: %s", control->description);
- pa_log_debug(" Mute: %s", pa_yes_no(control->mute));
- pa_log_debug(" Present: %s", pa_yes_no(control->present));
- pa_log_debug(" Persistent: %s", pa_yes_no(control->persistent));
- pa_log_debug(" Properties:");
-
- while ((prop_key = pa_proplist_iterate(control->proplist, &state)))
- pa_log_debug(" %s = %s", prop_key, pa_strnull(pa_proplist_gets(control->proplist, prop_key)));
-
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_PUT], control);
-}
-
-void pa_mute_control_unlink(pa_mute_control *control) {
- pa_device *device;
-
- pa_assert(control);
-
- if (control->unlinked) {
- pa_log_debug("Unlinking mute control %s (already unlinked, this is a no-op).", control->name);
- return;
- }
-
- control->unlinked = true;
-
- pa_log_debug("Unlinking mute control %s.", control->name);
-
- if (control->linked)
- pa_volume_api_remove_mute_control(control->volume_api, control);
-
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK], control);
-
- while ((device = pa_hashmap_first(control->default_for_devices)))
- pa_device_set_default_mute_control(device, NULL);
-
- while ((device = pa_hashmap_first(control->devices))) {
- /* Why do we have this assertion here? The concern is that if we call
- * pa_device_set_mute_control() for some device that has the
- * use_default_mute_control flag set, then that flag will be unset as
- * a side effect, and we don't want that side effect. This assertion
- * should be safe, because we just called
- * pa_device_set_default_mute_control(NULL) for each device that this
- * control was the default for, and that should ensure that we don't
- * any more hold any references to devices that used to use this
- * control as the default. */
- pa_assert(!device->use_default_mute_control);
- pa_device_set_mute_control(device, NULL);
- }
-}
-
-void pa_mute_control_free(pa_mute_control *control) {
- pa_assert(control);
-
- /* unlink() expects name to be set. */
- if (!control->unlinked && control->name)
- pa_mute_control_unlink(control);
-
- if (control->default_for_devices) {
- pa_assert(pa_hashmap_isempty(control->default_for_devices));
- pa_hashmap_free(control->default_for_devices);
- }
-
- if (control->devices) {
- pa_assert(pa_hashmap_isempty(control->devices));
- pa_hashmap_free(control->devices);
- }
-
- if (control->proplist)
- pa_proplist_free(control->proplist);
-
- pa_xfree(control->description);
-
- if (control->name)
- pa_volume_api_unregister_name(control->volume_api, control->name);
-
- pa_xfree(control);
-}
-
-void pa_mute_control_set_purpose(pa_mute_control *control, pa_mute_control_purpose_t purpose, void *owner) {
- pa_assert(control);
- pa_assert(!control->linked);
-
- control->purpose = purpose;
- control->owner = owner;
-}
-
-int pa_mute_control_acquire_for_audio_group(pa_mute_control *control, pa_audio_group *group,
- pa_mute_control_set_mute_cb_t set_mute_cb, void *userdata) {
- pa_assert(control);
- pa_assert(group);
- pa_assert(set_mute_cb);
-
- if (control->present) {
- pa_log("Can't acquire mute control %s, it's already present.", control->name);
- return -PA_ERR_BUSY;
- }
-
- control->owner_audio_group = group;
- control->set_mute = set_mute_cb;
- control->userdata = userdata;
-
- control->set_mute_in_progress = true;
- control->set_mute(control, control->mute);
- control->set_mute_in_progress = false;
-
- control->present = true;
-
- if (!control->linked || control->unlinked)
- return 0;
-
- pa_log_debug("Mute control %s became present.", control->name);
-
- return 0;
-}
-
-void pa_mute_control_release(pa_mute_control *control) {
- pa_assert(control);
-
- if (!control->present)
- return;
-
- control->present = false;
-
- control->userdata = NULL;
- control->set_mute = NULL;
- control->owner_audio_group = NULL;
-
- if (!control->linked || control->unlinked)
- return;
-
- pa_log_debug("Mute control %s became not present.", control->name);
-}
-
-void pa_mute_control_set_description(pa_mute_control *control, const char *description) {
- char *old_description;
-
- pa_assert(control);
- pa_assert(description);
-
- old_description = control->description;
-
- if (pa_streq(description, old_description))
- return;
-
- control->description = pa_xstrdup(description);
-
- if (control->persistent)
- pa_inidb_cell_set_value(control->db_cells.description, description);
-
- if (!control->linked || control->unlinked) {
- pa_xfree(old_description);
- return;
- }
-
- pa_log_debug("The description of mute control %s changed from \"%s\" to \"%s\".", control->name, old_description,
- description);
- pa_xfree(old_description);
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_DESCRIPTION_CHANGED], control);
-}
-
-static void set_mute_internal(pa_mute_control *control, bool mute) {
- bool old_mute;
-
- pa_assert(control);
-
- old_mute = control->mute;
-
- if (mute == old_mute)
- return;
-
- control->mute = mute;
-
- if (control->persistent)
- pa_inidb_cell_set_value(control->db_cells.mute, pa_boolean_to_string(mute));
-
- if (!control->linked || control->unlinked)
- return;
-
- pa_log_debug("The mute of mute control %s changed from %s to %s.", control->name, pa_boolean_to_string(old_mute),
- pa_boolean_to_string(control->mute));
-
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_MUTE_CHANGED], control);
-}
-
-int pa_mute_control_set_mute(pa_mute_control *control, bool mute) {
- int r;
-
- pa_assert(control);
-
- if (control->set_mute_in_progress)
- return 0;
-
- if (mute == control->mute)
- return 0;
-
- if (control->linked && control->present) {
- control->set_mute_in_progress = true;
- r = control->set_mute(control, mute);
- control->set_mute_in_progress = false;
-
- if (r < 0) {
- pa_log("Setting the mute of mute control %s failed.", control->name);
- return r;
- }
- }
-
- set_mute_internal(control, mute);
-
- return 0;
-}
-
-void pa_mute_control_add_device(pa_mute_control *control, pa_device *device) {
- pa_assert(control);
- pa_assert(device);
-
- pa_assert_se(pa_hashmap_put(control->devices, device, device) >= 0);
-}
-
-void pa_mute_control_remove_device(pa_mute_control *control, pa_device *device) {
- pa_assert(control);
- pa_assert(device);
-
- pa_assert_se(pa_hashmap_remove(control->devices, device));
-}
-
-void pa_mute_control_add_default_for_device(pa_mute_control *control, pa_device *device) {
- pa_assert(control);
- pa_assert(device);
-
- pa_assert_se(pa_hashmap_put(control->default_for_devices, device, device) >= 0);
-}
-
-void pa_mute_control_remove_default_for_device(pa_mute_control *control, pa_device *device) {
- pa_assert(control);
- pa_assert(device);
-
- pa_assert_se(pa_hashmap_remove(control->default_for_devices, device));
-}
+++ /dev/null
-#ifndef foomutecontrolhfoo
-#define foomutecontrolhfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <modules/volume-api/inidb.h>
-#include <modules/volume-api/volume-api.h>
-
-typedef struct pa_mute_control pa_mute_control;
-
-typedef enum {
- PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE,
- PA_MUTE_CONTROL_PURPOSE_OTHER,
-} pa_mute_control_purpose_t;
-
-typedef int (*pa_mute_control_set_mute_cb_t)(pa_mute_control *control, bool mute);
-
-struct pa_mute_control {
- pa_volume_api *volume_api;
- uint32_t index;
- const char *name;
- char *description;
- pa_proplist *proplist;
- bool mute;
- bool present;
- bool persistent;
-
- pa_mute_control_purpose_t purpose;
- union {
- pas_stream *owner_stream;
- void *owner;
- };
-
- /* If this mute control is the "own mute control" of an audio group, this
- * is set to point to that group, otherwise this is NULL. */
- pa_audio_group *owner_audio_group;
-
- pa_hashmap *devices; /* pa_device -> pa_device (hashmap-as-a-set) */
- pa_hashmap *default_for_devices; /* pa_device -> pa_device (hashmap-as-a-set) */
-
- struct {
- pa_inidb_cell *description;
- pa_inidb_cell *mute;
- } db_cells;
-
- bool linked;
- bool unlinked;
- bool set_mute_in_progress;
-
- /* Called from pa_mute_control_set_mute(). The implementation is expected
- * to return a negative error code on failure. */
- pa_mute_control_set_mute_cb_t set_mute;
-
- void *userdata;
-};
-
-int pa_mute_control_new(pa_volume_api *api, const char *name, bool persistent, pa_mute_control **_r);
-void pa_mute_control_put(pa_mute_control *control);
-void pa_mute_control_unlink(pa_mute_control *control);
-void pa_mute_control_free(pa_mute_control *control);
-
-/* Called by the mute control implementation, before pa_mute_control_put(). */
-void pa_mute_control_set_purpose(pa_mute_control *control, pa_mute_control_purpose_t purpose, void *owner);
-
-/* Called by the mute control implementation. */
-int pa_mute_control_acquire_for_audio_group(pa_mute_control *control, pa_audio_group *group,
- pa_mute_control_set_mute_cb_t set_mute_cb, void *userdata);
-
-/* Called by the mute control implementation. This must only be called for
- * persistent controls; use pa_mute_control_free() for non-persistent
- * controls. */
-void pa_mute_control_release(pa_mute_control *control);
-
-/* Called by anyone. */
-void pa_mute_control_set_description(pa_mute_control *control, const char *description);
-int pa_mute_control_set_mute(pa_mute_control *control, bool mute);
-
-/* Called from device.c only. */
-void pa_mute_control_add_device(pa_mute_control *control, pa_device *device);
-void pa_mute_control_remove_device(pa_mute_control *control, pa_device *device);
-void pa_mute_control_add_default_for_device(pa_mute_control *control, pa_device *device);
-void pa_mute_control_remove_default_for_device(pa_mute_control *control, pa_device *device);
-
-#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "sstream.h"
-
-#include <modules/volume-api/audio-group.h>
-#include <modules/volume-api/mute-control.h>
-#include <modules/volume-api/volume-control.h>
-
-#include <pulse/direction.h>
-
-#include <pulsecore/core-util.h>
-
-int pas_stream_new(pa_volume_api *api, const char *name, pas_stream **_r) {
- pas_stream *stream = NULL;
- int r;
-
- pa_assert(api);
- pa_assert(name);
- pa_assert(_r);
-
- stream = pa_xnew0(pas_stream, 1);
- stream->volume_api = api;
- stream->index = pa_volume_api_allocate_stream_index(api);
-
- r = pa_volume_api_register_name(api, name, false, &stream->name);
- if (r < 0)
- goto fail;
-
- stream->description = pa_xstrdup(stream->name);
- stream->direction = PA_DIRECTION_OUTPUT;
- stream->proplist = pa_proplist_new();
-
- *_r = stream;
- return 0;
-
-fail:
- if (stream)
- pas_stream_free(stream);
-
- return r;
-}
-
-void pas_stream_put(pas_stream *stream) {
- const char *prop_key;
- void *state = NULL;
-
- pa_assert(stream);
-
- pa_volume_api_add_stream(stream->volume_api, stream);
- stream->linked = true;
-
- pa_log_debug("Created stream #%u.", stream->index);
- pa_log_debug(" Name: %s", stream->name);
- pa_log_debug(" Description: %s", stream->description);
- pa_log_debug(" Direction: %s", pa_direction_to_string(stream->direction));
- pa_log_debug(" Volume control: %s", stream->volume_control ? stream->volume_control->name : "(unset)");
- pa_log_debug(" Mute control: %s", stream->mute_control ? stream->mute_control->name : "(unset)");
- pa_log_debug(" Audio group for volume: %s",
- stream->audio_group_for_volume ? stream->audio_group_for_volume->name : "(unset)");
- pa_log_debug(" Audio group for mute: %s",
- stream->audio_group_for_mute ? stream->audio_group_for_mute->name : "(unset)");
- pa_log_debug(" Properties:");
-
- while ((prop_key = pa_proplist_iterate(stream->proplist, &state)))
- pa_log_debug(" %s = %s", prop_key, pa_strnull(pa_proplist_gets(stream->proplist, prop_key)));
-
- pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_PUT], stream);
-}
-
-void pas_stream_unlink(pas_stream *stream) {
- pa_assert(stream);
-
- if (stream->unlinked) {
- pa_log_debug("Unlinking stream %s (already unlinked, this is a no-op).", stream->name);
- return;
- }
-
- stream->unlinked = true;
-
- pa_log_debug("Unlinking stream %s.", stream->name);
-
- if (stream->linked)
- pa_volume_api_remove_stream(stream->volume_api, stream);
-
- pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_UNLINK], stream);
-
- pas_stream_set_audio_group_for_mute(stream, NULL);
- pas_stream_set_audio_group_for_volume(stream, NULL);
- pas_stream_set_mute_control(stream, NULL);
- pas_stream_set_relative_volume_control(stream, NULL);
- pas_stream_set_volume_control(stream, NULL);
-}
-
-void pas_stream_free(pas_stream *stream) {
- pa_assert(stream);
-
- /* unlink() expects name to be set. */
- if (!stream->unlinked && stream->name)
- pas_stream_unlink(stream);
-
- if (stream->proplist)
- pa_proplist_free(stream->proplist);
-
- pa_xfree(stream->description);
-
- if (stream->name)
- pa_volume_api_unregister_name(stream->volume_api, stream->name);
-
- pa_xfree(stream);
-}
-
-void pas_stream_set_direction(pas_stream *stream, pa_direction_t direction) {
- pa_assert(stream);
- pa_assert(!stream->linked);
-
- stream->direction = direction;
-}
-
-void pas_stream_set_description(pas_stream *stream, const char *description) {
- char *old_description;
-
- pa_assert(stream);
- pa_assert(description);
-
- old_description = stream->description;
-
- if (pa_streq(description, old_description))
- return;
-
- stream->description = pa_xstrdup(description);
-
- if (!stream->linked || stream->unlinked) {
- pa_xfree(old_description);
- return;
- }
-
- pa_log_debug("Stream %s description changed from \"%s\" to \"%s\".", stream->name, old_description,
- description);
- pa_xfree(old_description);
-
- pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_DESCRIPTION_CHANGED], stream);
-}
-
-void pas_stream_set_property(pas_stream *stream, const char *key, const char *value) {
- const char *old_value;
-
- pa_assert(stream);
- pa_assert(key);
-
- old_value = pa_proplist_gets(stream->proplist, key);
-
- if (pa_safe_streq(value, old_value))
- return;
-
- if (value)
- pa_proplist_sets(stream->proplist, key, value);
- else
- pa_proplist_unset(stream->proplist, key);
-
- if (!stream->linked || stream->unlinked)
- return;
-
- pa_log_debug("Stream %s property \"%s\" changed from \"%s\" to \"%s\".", stream->name, key,
- old_value ? old_value : "(unset)", value ? value : "(unset)");
-
- pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_PROPLIST_CHANGED], stream);
-}
-
-void pas_stream_set_volume_control(pas_stream *stream, pa_volume_control *control) {
- pa_volume_control *old_control;
-
- pa_assert(stream);
-
- old_control = stream->volume_control;
-
- if (control == old_control)
- return;
-
- stream->volume_control = control;
-
- if (!stream->linked || stream->unlinked)
- return;
-
- pa_log_debug("The volume control of stream %s changed from %s to %s.", stream->name,
- old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-
- pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_VOLUME_CONTROL_CHANGED], stream);
-}
-
-void pas_stream_set_relative_volume_control(pas_stream *stream, pa_volume_control *control) {
- pa_volume_control *old_control;
-
- pa_assert(stream);
-
- old_control = stream->relative_volume_control;
-
- if (control == old_control)
- return;
-
- stream->relative_volume_control = control;
-
- if (!stream->linked || stream->unlinked)
- return;
-
- pa_log_debug("The relative volume control of stream %s changed from %s to %s.", stream->name,
- old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-
- pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_RELATIVE_VOLUME_CONTROL_CHANGED], stream);
-}
-
-void pas_stream_set_mute_control(pas_stream *stream, pa_mute_control *control) {
- pa_mute_control *old_control;
-
- pa_assert(stream);
-
- old_control = stream->mute_control;
-
- if (control == old_control)
- return;
-
- stream->mute_control = control;
-
- if (!stream->linked || stream->unlinked)
- return;
-
- pa_log_debug("The mute control of stream %s changed from %s to %s.", stream->name,
- old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-
- pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_MUTE_CONTROL_CHANGED], stream);
-}
-
-void pas_stream_set_audio_group_for_volume(pas_stream *stream, pa_audio_group *group) {
- pa_audio_group *old_group;
-
- pa_assert(stream);
-
- old_group = stream->audio_group_for_volume;
-
- if (group == old_group)
- return;
-
- if (old_group)
- pa_audio_group_remove_volume_stream(old_group, stream);
-
- stream->audio_group_for_volume = group;
-
- if (group)
- pa_audio_group_add_volume_stream(group, stream);
-
- if (!stream->linked || stream->unlinked)
- return;
-
- pa_log_debug("Stream %s audio group for volume changed from %s to %s.", stream->name,
- old_group ? old_group->name : "(unset)", group ? group->name : "(unset)");
-}
-
-void pas_stream_set_audio_group_for_mute(pas_stream *stream, pa_audio_group *group) {
- pa_audio_group *old_group;
-
- pa_assert(stream);
-
- old_group = stream->audio_group_for_mute;
-
- if (group == old_group)
- return;
-
- if (old_group)
- pa_audio_group_remove_mute_stream(old_group, stream);
-
- stream->audio_group_for_mute = group;
-
- if (group)
- pa_audio_group_add_mute_stream(group, stream);
-
- if (!stream->linked || stream->unlinked)
- return;
-
- pa_log_debug("Stream %s audio group for mute changed from %s to %s.", stream->name,
- old_group ? old_group->name : "(unset)", group ? group->name : "(unset)");
-}
+++ /dev/null
-#ifndef foosstreamhfoo
-#define foosstreamhfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <modules/volume-api/volume-api.h>
-
-/* We use the "pas_" prefix in pas_stream, because there's already pa_stream in
- * the client API, and there's no good alternative term for streams. The 's' in
- * "pas" means "server", i.e. the point is that this stuff is for servers,
- * while pa_stream is for clients. */
-
-typedef struct pas_stream pas_stream;
-
-struct pas_stream {
- pa_volume_api *volume_api;
- uint32_t index;
- const char *name;
- char *description;
- pa_direction_t direction;
- pa_proplist *proplist;
- pa_volume_control *volume_control;
- pa_volume_control *relative_volume_control;
- pa_mute_control *mute_control;
- pa_audio_group *audio_group_for_volume;
- pa_audio_group *audio_group_for_mute;
-
- bool linked;
- bool unlinked;
-
- void *userdata;
-};
-
-int pas_stream_new(pa_volume_api *api, const char *name, pas_stream **_r);
-void pas_stream_put(pas_stream *stream);
-void pas_stream_unlink(pas_stream *stream);
-void pas_stream_free(pas_stream *stream);
-
-/* Called by the stream implementation, only during initialization. */
-void pas_stream_set_direction(pas_stream *stream, pa_direction_t direction);
-
-/* Called by the stream implementation. */
-void pas_stream_set_description(pas_stream *stream, const char *description);
-void pas_stream_set_property(pas_stream *stream, const char *key, const char *value);
-void pas_stream_set_volume_control(pas_stream *stream, pa_volume_control *control);
-void pas_stream_set_relative_volume_control(pas_stream *stream, pa_volume_control *control);
-void pas_stream_set_mute_control(pas_stream *stream, pa_mute_control *control);
-
-/* Called by anyone. */
-void pas_stream_set_audio_group_for_volume(pas_stream *stream, pa_audio_group *group);
-void pas_stream_set_audio_group_for_mute(pas_stream *stream, pa_audio_group *group);
-
-#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "stream-creator.h"
-
-#include <modules/volume-api/sstream.h>
-#include <modules/volume-api/mute-control.h>
-#include <modules/volume-api/volume-control.h>
-
-#include <pulsecore/core-util.h>
-#include <pulsecore/i18n.h>
-
-struct pa_stream_creator {
- pa_volume_api *volume_api;
- pa_hashmap *streams; /* pa_sink_input/pa_source_output -> struct stream */
- pa_hook_slot *sink_input_fixate_slot;
- pa_hook_slot *sink_input_unlink_slot;
- pa_hook_slot *source_output_fixate_slot;
- pa_hook_slot *source_output_unlink_slot;
-};
-
-enum stream_type {
- STREAM_TYPE_SINK_INPUT,
- STREAM_TYPE_SOURCE_OUTPUT,
-};
-
-struct stream {
- pa_core *core;
- pa_stream_creator *creator;
- enum stream_type type;
- pa_sink_input_new_data *sink_input_new_data;
- pa_sink_input *sink_input;
- pa_source_output_new_data *source_output_new_data;
- pa_source_output *source_output;
- pa_client *client;
- pa_volume_control *volume_control;
- pa_volume_control *relative_volume_control;
- pa_mute_control *mute_control;
- pas_stream *stream;
-
- pa_hook_slot *proplist_changed_slot;
- pa_hook_slot *volume_changed_slot;
- pa_hook_slot *reference_ratio_changed_slot;
- pa_hook_slot *mute_changed_slot;
-};
-
-static void stream_free(struct stream *stream);
-
-static int volume_control_set_volume_cb(pa_volume_control *control, const pa_bvolume *original_volume,
- const pa_bvolume *remapped_volume, bool set_volume, bool set_balance) {
- struct stream *stream;
- pa_bvolume bvolume;
- pa_cvolume cvolume;
-
- pa_assert(control);
- pa_assert(original_volume);
- pa_assert(remapped_volume);
-
- stream = control->userdata;
- bvolume = control->volume;
-
- if (set_volume)
- bvolume.volume = remapped_volume->volume;
-
- if (set_balance)
- pa_bvolume_copy_balance(&bvolume, remapped_volume);
-
- pa_bvolume_to_cvolume(&bvolume, &cvolume);
-
- switch (stream->type) {
- case STREAM_TYPE_SINK_INPUT:
- if (stream->sink_input->state == PA_SINK_INPUT_INIT)
- pa_sink_input_new_data_set_volume(stream->sink_input_new_data, &cvolume, false);
- else
- pa_sink_input_set_volume(stream->sink_input, &cvolume, true, true);
- break;
-
- case STREAM_TYPE_SOURCE_OUTPUT:
- if (stream->source_output->state == PA_SOURCE_OUTPUT_INIT)
- pa_source_output_new_data_set_volume(stream->source_output_new_data, &cvolume, false);
- else
- pa_source_output_set_volume(stream->source_output, &cvolume, true, true);
- break;
- }
-
- return 0;
-}
-
-static pa_hook_result_t sink_input_or_source_output_volume_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct stream *stream = userdata;
- pa_sink_input *input = NULL;
- pa_source_output *output = NULL;
- pa_bvolume bvolume;
-
- pa_assert(stream);
- pa_assert(call_data);
-
- if (!stream->volume_control)
- return PA_HOOK_OK;
-
- switch (stream->type) {
- case STREAM_TYPE_SINK_INPUT:
- input = call_data;
- break;
-
- case STREAM_TYPE_SOURCE_OUTPUT:
- output = call_data;
- break;
- }
-
- if ((input && input != stream->sink_input) || (output && output != stream->source_output))
- return PA_HOOK_OK;
-
- if (input)
- pa_bvolume_from_cvolume(&bvolume, &input->volume, &input->channel_map);
- else if (output)
- pa_bvolume_from_cvolume(&bvolume, &output->volume, &output->channel_map);
- else
- pa_assert_not_reached();
-
- pa_volume_control_set_volume(stream->volume_control, &bvolume, true, true);
-
- return PA_HOOK_OK;
-}
-
-static int relative_volume_control_set_volume_cb(pa_volume_control *control, const pa_bvolume *original_volume,
- const pa_bvolume *remapped_volume, bool set_volume, bool set_balance) {
- struct stream *stream;
- pa_bvolume bvolume;
- pa_cvolume cvolume;
-
- pa_assert(control);
- pa_assert(original_volume);
- pa_assert(remapped_volume);
-
- stream = control->userdata;
- bvolume = control->volume;
-
- if (set_volume)
- bvolume.volume = remapped_volume->volume;
-
- if (set_balance)
- pa_bvolume_copy_balance(&bvolume, remapped_volume);
-
- pa_bvolume_to_cvolume(&bvolume, &cvolume);
-
- switch (stream->type) {
- case STREAM_TYPE_SINK_INPUT:
- if (stream->sink_input->state == PA_SINK_INPUT_INIT) {
- pa_sink_input_new_data_set_volume(stream->sink_input_new_data, &cvolume, true);
-
- /* XXX: This is a bit ugly. This is needed, because when we
- * call pa_sink_input_new_data_set_volume(), there's no
- * automatic notification to the primary volume control object
- * about the changed volume. This problem should go away once
- * stream volume controls are moved into the core. */
- if (stream->volume_control) {
- pa_bvolume absolute_volume;
-
- pa_bvolume_from_cvolume(&absolute_volume, &stream->sink_input_new_data->volume,
- &stream->sink_input_new_data->channel_map);
- pa_volume_control_set_volume(stream->volume_control, &absolute_volume, true, true);
- }
- } else
- pa_sink_input_set_volume(stream->sink_input, &cvolume, true, false);
- break;
-
- case STREAM_TYPE_SOURCE_OUTPUT:
- if (stream->source_output->state == PA_SOURCE_OUTPUT_INIT) {
- pa_source_output_new_data_set_volume(stream->source_output_new_data, &cvolume, true);
-
- /* XXX: This is a bit ugly. This is needed, because when we
- * call pa_source_output_new_data_set_volume(), there's no
- * automatic notification to the primary volume control object
- * about the changed volume. This problem should go away once
- * stream volume controls are moved into the core. */
- if (stream->volume_control) {
- pa_bvolume absolute_volume;
-
- pa_bvolume_from_cvolume(&absolute_volume, &stream->source_output_new_data->volume,
- &stream->source_output_new_data->channel_map);
- pa_volume_control_set_volume(stream->volume_control, &absolute_volume, true, true);
- }
- } else
- pa_source_output_set_volume(stream->source_output, &cvolume, true, false);
- break;
- }
-
- return 0;
-}
-
-static pa_hook_result_t sink_input_or_source_output_reference_ratio_changed_cb(void *hook_data, void *call_data,
- void *userdata) {
- struct stream *stream = userdata;
- pa_sink_input *input = NULL;
- pa_source_output *output = NULL;
- pa_bvolume bvolume;
-
- pa_assert(stream);
- pa_assert(call_data);
-
- if (!stream->relative_volume_control)
- return PA_HOOK_OK;
-
- switch (stream->type) {
- case STREAM_TYPE_SINK_INPUT:
- input = call_data;
- break;
-
- case STREAM_TYPE_SOURCE_OUTPUT:
- output = call_data;
- break;
- }
-
- if ((input && input != stream->sink_input) || (output && output != stream->source_output))
- return PA_HOOK_OK;
-
- if (input)
- pa_bvolume_from_cvolume(&bvolume, &input->reference_ratio, &input->channel_map);
- else if (output)
- pa_bvolume_from_cvolume(&bvolume, &output->reference_ratio, &output->channel_map);
- else
- pa_assert_not_reached();
-
- pa_volume_control_set_volume(stream->relative_volume_control, &bvolume, true, true);
-
- return PA_HOOK_OK;
-}
-
-static int mute_control_set_mute_cb(pa_mute_control *control, bool mute) {
- struct stream *stream;
-
- pa_assert(control);
-
- stream = control->userdata;
-
- switch (stream->type) {
- case STREAM_TYPE_SINK_INPUT:
- if (stream->sink_input->state == PA_SINK_INPUT_INIT)
- pa_sink_input_new_data_set_muted(stream->sink_input_new_data, mute);
- else
- pa_sink_input_set_mute(stream->sink_input, mute, true);
- break;
-
- case STREAM_TYPE_SOURCE_OUTPUT:
- if (stream->source_output->state == PA_SOURCE_OUTPUT_INIT)
- pa_source_output_new_data_set_muted(stream->source_output_new_data, mute);
- else
- pa_source_output_set_mute(stream->source_output, mute, true);
- break;
- }
-
- return 0;
-}
-
-static pa_hook_result_t sink_input_or_source_output_mute_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct stream *stream = userdata;
- pa_sink_input *input = NULL;
- pa_source_output *output = NULL;
- bool mute;
-
- pa_assert(stream);
- pa_assert(call_data);
-
- if (!stream->mute_control)
- return PA_HOOK_OK;
-
- switch (stream->type) {
- case STREAM_TYPE_SINK_INPUT:
- input = call_data;
- break;
-
- case STREAM_TYPE_SOURCE_OUTPUT:
- output = call_data;
- break;
- }
-
- if ((input && input != stream->sink_input) || (output && output != stream->source_output))
- return PA_HOOK_OK;
-
- if (input)
- mute = input->muted;
- else if (output)
- mute = output->muted;
- else
- pa_assert_not_reached();
-
- pa_mute_control_set_mute(stream->mute_control, mute);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t sink_input_or_source_output_proplist_changed_cb(void *hook_data, void *call_data, void *userdata) {
- struct stream *stream = userdata;
- pa_sink_input *input = NULL;
- pa_source_output *output = NULL;
- pa_proplist *proplist = NULL;
- const char *description = NULL;
-
- pa_assert(stream);
- pa_assert(call_data);
-
- switch (stream->type) {
- case STREAM_TYPE_SINK_INPUT:
- input = call_data;
-
- if (input != stream->sink_input)
- return PA_HOOK_OK;
-
- proplist = stream->sink_input->proplist;
- break;
-
- case STREAM_TYPE_SOURCE_OUTPUT:
- output = call_data;
-
- if (output != stream->source_output)
- return PA_HOOK_OK;
-
- proplist = stream->source_output->proplist;
- break;
- }
-
- description = pa_proplist_gets(proplist, PA_PROP_MEDIA_NAME);
- if (!description)
- description = stream->stream->name;
-
- pas_stream_set_description(stream->stream, description);
-
- return PA_HOOK_OK;
-}
-
-static int stream_new(pa_stream_creator *creator, enum stream_type type, void *new_data, void *core_stream,
- struct stream **_r) {
- struct stream *stream = NULL;
- pa_proplist *proplist = NULL;
- pa_channel_map *channel_map = NULL;
- bool volume_available = false;
- pa_bvolume volume;
- pa_bvolume relative_volume;
- bool mute = false;
- const char *stream_name = NULL;
- const char *description = NULL;
- const char *volume_control_name = NULL;
- const char *relative_volume_control_name = NULL;
- const char *mute_control_name = NULL;
- pa_direction_t direction = PA_DIRECTION_OUTPUT;
- int r;
- const char *prop_key;
- void *state = NULL;
-
- pa_assert(creator);
- pa_assert(core_stream);
- pa_assert(_r);
-
- pa_bvolume_init_invalid(&volume);
- pa_bvolume_init_invalid(&relative_volume);
-
- stream = pa_xnew0(struct stream, 1);
- stream->core = creator->volume_api->core;
- stream->creator = creator;
- stream->type = type;
-
- switch (type) {
- case STREAM_TYPE_SINK_INPUT:
- stream->sink_input_new_data = new_data;
- stream->sink_input = core_stream;
-
- if (new_data) {
- stream->client = stream->sink_input_new_data->client;
- proplist = stream->sink_input_new_data->proplist;
- channel_map = &stream->sink_input_new_data->channel_map;
- volume_available = stream->sink_input_new_data->volume_writable;
-
- if (volume_available) {
- if (!stream->sink_input_new_data->volume_is_set) {
- pa_cvolume cvolume;
-
- pa_cvolume_reset(&cvolume, channel_map->channels);
- pa_sink_input_new_data_set_volume(stream->sink_input_new_data, &cvolume, true);
- }
-
- pa_bvolume_from_cvolume(&volume, &stream->sink_input_new_data->volume, channel_map);
- pa_bvolume_from_cvolume(&relative_volume, &stream->sink_input_new_data->reference_ratio, channel_map);
- }
-
- if (!stream->sink_input_new_data->muted_is_set)
- pa_sink_input_new_data_set_muted(stream->sink_input_new_data, false);
-
- mute = stream->sink_input_new_data->muted;
- } else {
- stream->client = stream->sink_input->client;
- proplist = stream->sink_input->proplist;
- channel_map = &stream->sink_input->channel_map;
- pa_bvolume_from_cvolume(&volume, &stream->sink_input->volume, channel_map);
- pa_bvolume_from_cvolume(&relative_volume, &stream->sink_input->reference_ratio, channel_map);
- mute = stream->sink_input->muted;
- }
-
- stream_name = "sink-input-stream";
- volume_control_name = "sink-input-volume-control";
- relative_volume_control_name = "sink-input-relative-volume-control";
- mute_control_name = "sink-input-mute-control";
-
- direction = PA_DIRECTION_OUTPUT;
-
- stream->proplist_changed_slot =
- pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], PA_HOOK_NORMAL,
- sink_input_or_source_output_proplist_changed_cb, stream);
- stream->volume_changed_slot =
- pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED], PA_HOOK_NORMAL,
- sink_input_or_source_output_volume_changed_cb, stream);
- stream->reference_ratio_changed_slot =
- pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SINK_INPUT_REFERENCE_RATIO_CHANGED], PA_HOOK_NORMAL,
- sink_input_or_source_output_reference_ratio_changed_cb, stream);
- stream->mute_changed_slot =
- pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED], PA_HOOK_NORMAL,
- sink_input_or_source_output_mute_changed_cb, stream);
- break;
-
- case STREAM_TYPE_SOURCE_OUTPUT:
- stream->source_output_new_data = new_data;
- stream->source_output = core_stream;
-
- if (new_data) {
- stream->client = stream->source_output_new_data->client;
- proplist = stream->source_output_new_data->proplist;
- channel_map = &stream->source_output_new_data->channel_map;
- volume_available = stream->source_output_new_data->volume_writable;
-
- if (volume_available) {
- if (!stream->source_output_new_data->volume_is_set) {
- pa_cvolume cvolume;
-
- pa_cvolume_reset(&cvolume, channel_map->channels);
- pa_source_output_new_data_set_volume(stream->source_output_new_data, &cvolume, true);
- }
-
- pa_bvolume_from_cvolume(&volume, &stream->source_output_new_data->volume, channel_map);
- pa_bvolume_from_cvolume(&relative_volume, &stream->source_output_new_data->reference_ratio, channel_map);
- }
-
- if (!stream->source_output_new_data->muted_is_set)
- pa_source_output_new_data_set_muted(stream->source_output_new_data, false);
-
- mute = stream->source_output_new_data->muted;
- } else {
- stream->client = stream->source_output->client;
- proplist = stream->source_output->proplist;
- channel_map = &stream->source_output->channel_map;
- pa_bvolume_from_cvolume(&volume, &stream->source_output->volume, channel_map);
- pa_bvolume_from_cvolume(&relative_volume, &stream->source_output->reference_ratio, channel_map);
- mute = stream->source_output->muted;
- }
-
- stream_name = "source-output-stream";
- volume_control_name = "source-output-volume-control";
- relative_volume_control_name = "source-output-relative-volume-control";
- mute_control_name = "source-output-mute-control";
-
- direction = PA_DIRECTION_INPUT;
-
- stream->proplist_changed_slot =
- pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], PA_HOOK_NORMAL,
- sink_input_or_source_output_proplist_changed_cb, stream);
-
- if (volume_available) {
- stream->volume_changed_slot =
- pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED], PA_HOOK_NORMAL,
- sink_input_or_source_output_volume_changed_cb, stream);
- stream->reference_ratio_changed_slot =
- pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_REFERENCE_RATIO_CHANGED],
- PA_HOOK_NORMAL, sink_input_or_source_output_reference_ratio_changed_cb, stream);
- }
-
- stream->mute_changed_slot =
- pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED], PA_HOOK_NORMAL,
- sink_input_or_source_output_mute_changed_cb, stream);
- break;
- }
-
- r = pas_stream_new(creator->volume_api, stream_name, &stream->stream);
- if (r < 0)
- goto fail;
-
- description = pa_proplist_gets(proplist, PA_PROP_MEDIA_NAME);
- if (!description)
- description = stream->stream->name;
-
- pas_stream_set_description(stream->stream, description);
-
- while ((prop_key = pa_proplist_iterate(proplist, &state)))
- pas_stream_set_property(stream->stream, prop_key, pa_proplist_gets(proplist, prop_key));
-
- pas_stream_set_direction(stream->stream, direction);
- stream->stream->userdata = stream;
-
- if (volume_available) {
- r = pa_volume_control_new(stream->creator->volume_api, volume_control_name, false,
- &stream->volume_control);
- if (r >= 0) {
- pa_volume_control_set_description(stream->volume_control, _("Volume"));
- pa_volume_control_set_channel_map(stream->volume_control, channel_map);
- pa_volume_control_set_volume(stream->volume_control, &volume, true, true);
- pa_volume_control_set_convertible_to_dB(stream->volume_control, true);
- stream->volume_control->set_volume = volume_control_set_volume_cb;
- stream->volume_control->userdata = stream;
-
- pas_stream_set_volume_control(stream->stream, stream->volume_control);
- }
-
- r = pa_volume_control_new(stream->creator->volume_api, relative_volume_control_name, false,
- &stream->relative_volume_control);
- if (r >= 0) {
- pa_volume_control_set_description(stream->relative_volume_control, _("Relative volume"));
- pa_volume_control_set_channel_map(stream->relative_volume_control, channel_map);
- pa_volume_control_set_volume(stream->relative_volume_control, &relative_volume, true, true);
- pa_volume_control_set_convertible_to_dB(stream->relative_volume_control, true);
- pa_volume_control_set_purpose(stream->relative_volume_control, PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME,
- stream->stream);
- stream->relative_volume_control->set_volume = relative_volume_control_set_volume_cb;
- stream->relative_volume_control->userdata = stream;
-
- pas_stream_set_relative_volume_control(stream->stream, stream->relative_volume_control);
- }
- }
-
- r = pa_mute_control_new(stream->creator->volume_api, mute_control_name, false, &stream->mute_control);
- if (r >= 0) {
- pa_mute_control_set_description(stream->mute_control, _("Mute"));
- pa_mute_control_set_mute(stream->mute_control, mute);
- pa_mute_control_set_purpose(stream->mute_control, PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE, stream->stream);
- stream->mute_control->set_mute = mute_control_set_mute_cb;
- stream->mute_control->userdata = stream;
-
- pas_stream_set_mute_control(stream->stream, stream->mute_control);
- }
-
- pas_stream_put(stream->stream);
-
- if (stream->volume_control)
- pa_volume_control_put(stream->volume_control);
-
- if (stream->relative_volume_control)
- pa_volume_control_put(stream->relative_volume_control);
-
- if (stream->mute_control)
- pa_mute_control_put(stream->mute_control);
-
- *_r = stream;
- return 0;
-
-fail:
- if (stream)
- stream_free(stream);
-
- return r;
-}
-
-static void stream_free(struct stream *stream) {
- pa_assert(stream);
-
- if (stream->mute_changed_slot)
- pa_hook_slot_free(stream->mute_changed_slot);
-
- if (stream->reference_ratio_changed_slot)
- pa_hook_slot_free(stream->reference_ratio_changed_slot);
-
- if (stream->volume_changed_slot)
- pa_hook_slot_free(stream->volume_changed_slot);
-
- if (stream->proplist_changed_slot)
- pa_hook_slot_free(stream->proplist_changed_slot);
-
- if (stream->mute_control)
- pa_mute_control_free(stream->mute_control);
-
- if (stream->relative_volume_control)
- pa_volume_control_free(stream->relative_volume_control);
-
- if (stream->volume_control)
- pa_volume_control_free(stream->volume_control);
-
- if (stream->stream)
- pas_stream_free(stream->stream);
-
- pa_xfree(stream);
-}
-
-static pa_hook_result_t sink_input_fixate_cb(void *hook_data, void *call_data, void *userdata) {
- pa_stream_creator *creator = userdata;
- pa_sink_input_new_data *data = call_data;
- int r;
- struct stream *stream;
-
- pa_assert(creator);
- pa_assert(data);
-
- r = stream_new(creator, STREAM_TYPE_SINK_INPUT, data, data->sink_input, &stream);
- if (r < 0)
- return PA_HOOK_OK;
-
- pa_hashmap_put(creator->streams, stream->sink_input, stream);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t sink_input_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- pa_stream_creator *creator = userdata;
- pa_sink_input *input = call_data;
-
- pa_assert(creator);
- pa_assert(input);
-
- pa_hashmap_remove_and_free(creator->streams, input);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t source_output_fixate_cb(void *hook_data, void *call_data, void *userdata) {
- pa_stream_creator *creator = userdata;
- pa_source_output_new_data *data = call_data;
- int r;
- struct stream *stream;
-
- pa_assert(creator);
- pa_assert(data);
-
- r = stream_new(creator, STREAM_TYPE_SOURCE_OUTPUT, data, data->source_output, &stream);
- if (r < 0)
- return PA_HOOK_OK;
-
- pa_hashmap_put(creator->streams, stream->source_output, stream);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t source_output_unlink_cb(void *hook_data, void *call_data, void *userdata) {
- pa_stream_creator *creator = userdata;
- pa_source_output *output = call_data;
-
- pa_assert(creator);
- pa_assert(output);
-
- pa_hashmap_remove_and_free(creator->streams, output);
-
- return PA_HOOK_OK;
-}
-
-pa_stream_creator *pa_stream_creator_new(pa_volume_api *api) {
- pa_stream_creator *creator;
- uint32_t idx;
- pa_sink_input *input;
- pa_source_output *output;
- int r;
- struct stream *stream;
-
- pa_assert(api);
-
- creator = pa_xnew0(pa_stream_creator, 1);
- creator->volume_api = api;
- creator->streams = pa_hashmap_new_full(NULL, NULL, NULL, (pa_free_cb_t) stream_free);
- creator->sink_input_fixate_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_NORMAL,
- sink_input_fixate_cb, creator);
- creator->sink_input_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_NORMAL,
- sink_input_unlink_cb, creator);
- creator->source_output_fixate_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], PA_HOOK_NORMAL,
- source_output_fixate_cb, creator);
- creator->source_output_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_NORMAL,
- source_output_unlink_cb, creator);
-
- PA_IDXSET_FOREACH(input, api->core->sink_inputs, idx) {
- r = stream_new(creator, STREAM_TYPE_SINK_INPUT, NULL, input, &stream);
- if (r >= 0)
- pa_hashmap_put(creator->streams, stream->sink_input, stream);
- }
-
- PA_IDXSET_FOREACH(output, api->core->source_outputs, idx) {
- r = stream_new(creator, STREAM_TYPE_SOURCE_OUTPUT, NULL, output, &stream);
- if (r >= 0)
- pa_hashmap_put(creator->streams, stream->source_output, stream);
- }
-
- return creator;
-}
-
-void pa_stream_creator_free(pa_stream_creator *creator) {
- pa_assert(creator);
-
- if (creator->streams)
- pa_hashmap_remove_all(creator->streams);
-
- if (creator->source_output_unlink_slot)
- pa_hook_slot_free(creator->source_output_unlink_slot);
-
- if (creator->source_output_fixate_slot)
- pa_hook_slot_free(creator->source_output_fixate_slot);
-
- if (creator->sink_input_unlink_slot)
- pa_hook_slot_free(creator->sink_input_unlink_slot);
-
- if (creator->sink_input_fixate_slot)
- pa_hook_slot_free(creator->sink_input_fixate_slot);
-
- if (creator->streams)
- pa_hashmap_free(creator->streams);
-
- pa_xfree(creator);
-}
+++ /dev/null
-#ifndef foostreamcreatorhfoo
-#define foostreamcreatorhfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <modules/volume-api/volume-api.h>
-
-typedef struct pa_stream_creator pa_stream_creator;
-
-pa_stream_creator *pa_stream_creator_new(pa_volume_api *api);
-void pa_stream_creator_free(pa_stream_creator *creator);
-
-#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#define PA_VOLUME_API_VERSION 1
-#define PA_VOLUME_API_EXTENSION_NAME "module-volume-api"
-
-enum {
- PA_VOLUME_API_COMMAND_CONNECT,
- PA_VOLUME_API_COMMAND_DISCONNECT,
- PA_VOLUME_API_COMMAND_SUBSCRIBE,
- PA_VOLUME_API_COMMAND_SUBSCRIBE_EVENT,
- PA_VOLUME_API_COMMAND_GET_SERVER_INFO,
- PA_VOLUME_API_COMMAND_GET_VOLUME_CONTROL_INFO,
- PA_VOLUME_API_COMMAND_GET_VOLUME_CONTROL_INFO_LIST,
- PA_VOLUME_API_COMMAND_SET_VOLUME_CONTROL_VOLUME,
- PA_VOLUME_API_COMMAND_GET_MUTE_CONTROL_INFO,
- PA_VOLUME_API_COMMAND_GET_MUTE_CONTROL_INFO_LIST,
- PA_VOLUME_API_COMMAND_SET_MUTE_CONTROL_MUTE,
- PA_VOLUME_API_COMMAND_GET_DEVICE_INFO,
- PA_VOLUME_API_COMMAND_GET_DEVICE_INFO_LIST,
- PA_VOLUME_API_COMMAND_GET_STREAM_INFO,
- PA_VOLUME_API_COMMAND_GET_STREAM_INFO_LIST,
- PA_VOLUME_API_COMMAND_GET_AUDIO_GROUP_INFO,
- PA_VOLUME_API_COMMAND_GET_AUDIO_GROUP_INFO_LIST
-};
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "volume-api.h"
-
-#include <modules/volume-api/audio-group.h>
-#include <modules/volume-api/device.h>
-#include <modules/volume-api/device-creator.h>
-#include <modules/volume-api/inidb.h>
-#include <modules/volume-api/sstream.h>
-#include <modules/volume-api/stream-creator.h>
-#include <modules/volume-api/volume-control.h>
-
-#include <pulsecore/core-util.h>
-#include <pulsecore/namereg.h>
-#include <pulsecore/shared.h>
-
-#define CONTROL_DB_TABLE_NAME_VOLUME_CONTROL "VolumeControl"
-#define CONTROL_DB_TABLE_NAME_MUTE_CONTROL "MuteControl"
-
-static pa_volume_api *volume_api_new(pa_core *core);
-static void volume_api_free(pa_volume_api *api);
-
-pa_volume_api *pa_volume_api_get(pa_core *core) {
- pa_volume_api *api;
-
- pa_assert(core);
-
- api = pa_shared_get(core, "volume-api");
-
- if (api)
- pa_volume_api_ref(api);
- else {
- api = volume_api_new(core);
- pa_assert_se(pa_shared_set(core, "volume-api", api) >= 0);
- }
-
- return api;
-}
-
-pa_volume_api *pa_volume_api_ref(pa_volume_api *api) {
- pa_assert(api);
-
- api->refcnt++;
-
- return api;
-}
-
-void pa_volume_api_unref(pa_volume_api *api) {
- pa_assert(api);
- pa_assert(api->refcnt > 0);
-
- api->refcnt--;
-
- if (api->refcnt == 0) {
- pa_assert_se(pa_shared_remove(api->core, "volume-api") >= 0);
- volume_api_free(api);
- }
-}
-
-static int control_db_get_volume_control_cb(pa_inidb *db, const char *name, void **_r) {
- pa_volume_api *api;
- pa_volume_control *control;
-
- pa_assert(db);
- pa_assert(name);
- pa_assert(_r);
-
- api = pa_inidb_get_userdata(db);
-
- control = pa_hashmap_get(api->volume_controls_from_db, name);
- if (!control) {
- int r;
-
- r = pa_volume_control_new(api, name, true, &control);
- if (r < 0)
- return r;
-
- pa_hashmap_put(api->volume_controls_from_db, (void *) control->name, control);
- }
-
- *_r = control;
- return 0;
-}
-
-static int control_db_parse_volume_control_description_cb(pa_inidb *db, const char *value, void *object) {
- pa_volume_control *control = object;
-
- pa_assert(db);
- pa_assert(value);
- pa_assert(control);
-
- pa_volume_control_set_description(control, value);
-
- return 0;
-}
-
-static int control_db_parse_volume_control_volume_cb(pa_inidb *db, const char *value, void *object) {
- pa_volume_control *control = object;
- int r;
- pa_bvolume bvolume;
-
- pa_assert(db);
- pa_assert(value);
- pa_assert(control);
-
- r = pa_atou(value, &bvolume.volume);
- if (r < 0)
- return -PA_ERR_INVALID;
-
- if (!PA_VOLUME_IS_VALID(bvolume.volume))
- return -PA_ERR_INVALID;
-
- pa_volume_control_set_volume(control, &bvolume, true, false);
-
- return 0;
-}
-
-static int control_db_parse_volume_control_balance_cb(pa_inidb *db, const char *value, void *object) {
- pa_volume_control *control = object;
- int r;
- pa_bvolume bvolume;
-
- pa_assert(db);
- pa_assert(value);
- pa_assert(control);
-
- r = pa_bvolume_parse_balance(value, &bvolume);
- if (r < 0)
- return -PA_ERR_INVALID;
-
- pa_volume_control_set_channel_map(control, &bvolume.channel_map);
- pa_volume_control_set_volume(control, &bvolume, false, true);
-
- return 0;
-}
-
-static int control_db_parse_volume_control_convertible_to_dB_cb(pa_inidb *db, const char *value, void *object) {
- pa_volume_control *control = object;
- int r;
-
- pa_assert(db);
- pa_assert(value);
- pa_assert(control);
-
- r = pa_parse_boolean(value);
- if (r < 0)
- return -PA_ERR_INVALID;
-
- pa_volume_control_set_convertible_to_dB(control, r);
-
- return 0;
-}
-
-static int control_db_get_mute_control_cb(pa_inidb *db, const char *name, void **_r) {
- pa_volume_api *api;
- pa_mute_control *control;
-
- pa_assert(db);
- pa_assert(name);
- pa_assert(_r);
-
- api = pa_inidb_get_userdata(db);
-
- control = pa_hashmap_get(api->mute_controls_from_db, name);
- if (!control) {
- int r;
-
- r = pa_mute_control_new(api, name, true, &control);
- if (r < 0)
- return r;
-
- pa_hashmap_put(api->mute_controls_from_db, (void *) control->name, control);
- }
-
- *_r = control;
- return 0;
-}
-
-static int control_db_parse_mute_control_description_cb(pa_inidb *db, const char *value, void *object) {
- pa_mute_control *control = object;
-
- pa_assert(db);
- pa_assert(value);
- pa_assert(control);
-
- pa_mute_control_set_description(control, value);
-
- return 0;
-}
-
-static int control_db_parse_mute_control_mute_cb(pa_inidb *db, const char *value, void *object) {
- pa_mute_control *control = object;
- int mute;
-
- pa_assert(db);
- pa_assert(value);
- pa_assert(control);
-
- mute = pa_parse_boolean(value);
- if (mute < 0)
- return -PA_ERR_INVALID;
-
- pa_mute_control_set_mute(control, mute);
-
- return 0;
-}
-
-static void create_control_db(pa_volume_api *api) {
- pa_volume_control *volume_control;
- pa_mute_control *mute_control;
-
- pa_assert(api);
- pa_assert(!api->control_db.db);
-
- api->control_db.db = pa_inidb_new(api->core, "controls", api);
-
- api->control_db.volume_controls = pa_inidb_add_table(api->control_db.db, CONTROL_DB_TABLE_NAME_VOLUME_CONTROL,
- control_db_get_volume_control_cb);
- pa_inidb_table_add_column(api->control_db.volume_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_DESCRIPTION,
- control_db_parse_volume_control_description_cb);
- pa_inidb_table_add_column(api->control_db.volume_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_VOLUME,
- control_db_parse_volume_control_volume_cb);
- pa_inidb_table_add_column(api->control_db.volume_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_BALANCE,
- control_db_parse_volume_control_balance_cb);
- pa_inidb_table_add_column(api->control_db.volume_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_CONVERTIBLE_TO_DB,
- control_db_parse_volume_control_convertible_to_dB_cb);
-
- api->control_db.mute_controls = pa_inidb_add_table(api->control_db.db, CONTROL_DB_TABLE_NAME_MUTE_CONTROL,
- control_db_get_mute_control_cb);
- pa_inidb_table_add_column(api->control_db.mute_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_DESCRIPTION,
- control_db_parse_mute_control_description_cb);
- pa_inidb_table_add_column(api->control_db.mute_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_MUTE,
- control_db_parse_mute_control_mute_cb);
-
- api->volume_controls_from_db = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
- api->mute_controls_from_db = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-
- pa_inidb_load(api->control_db.db);
-
- while ((volume_control = pa_hashmap_steal_first(api->volume_controls_from_db)))
- pa_volume_control_put(volume_control);
-
- pa_hashmap_free(api->volume_controls_from_db);
- api->volume_controls_from_db = NULL;
-
- while ((mute_control = pa_hashmap_steal_first(api->mute_controls_from_db)))
- pa_mute_control_put(mute_control);
-
- pa_hashmap_free(api->mute_controls_from_db);
- api->mute_controls_from_db = NULL;
-}
-
-static void delete_control_db(pa_volume_api *api) {
- pa_assert(api);
-
- if (!api->control_db.db)
- return;
-
- pa_inidb_free(api->control_db.db);
- api->control_db.mute_controls = NULL;
- api->control_db.volume_controls = NULL;
- api->control_db.db = NULL;
-}
-
-static void create_objects_defer_event_cb(pa_mainloop_api *mainloop_api, pa_defer_event *event, void *userdata) {
- pa_volume_api *volume_api = userdata;
-
- pa_assert(volume_api);
- pa_assert(event == volume_api->create_objects_defer_event);
-
- mainloop_api->defer_free(event);
- volume_api->create_objects_defer_event = NULL;
-
- volume_api->device_creator = pa_device_creator_new(volume_api);
- volume_api->stream_creator = pa_stream_creator_new(volume_api);
-}
-
-static pa_volume_api *volume_api_new(pa_core *core) {
- pa_volume_api *api;
- unsigned i;
-
- pa_assert(core);
-
- api = pa_xnew0(pa_volume_api, 1);
- api->core = core;
- api->refcnt = 1;
- api->names = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
- api->volume_controls = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
- api->mute_controls = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
- api->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
- api->streams = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
- api->audio_groups = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-
- for (i = 0; i < PA_VOLUME_API_HOOK_MAX; i++)
- pa_hook_init(&api->hooks[i], api);
-
- create_control_db(api);
-
- /* We delay the object creation to ensure that policy modules have a chance
- * to affect the initialization of the objects. If we created the objects
- * immediately, policy modules wouldn't have a chance of connecting to the
- * object creation hooks before the objects are created. */
- api->create_objects_defer_event = core->mainloop->defer_new(core->mainloop, create_objects_defer_event_cb, api);
-
- pa_log_debug("Created a pa_volume_api object.");
-
- return api;
-}
-
-static void volume_api_free(pa_volume_api *api) {
- unsigned i;
-
- pa_assert(api);
- pa_assert(api->refcnt == 0);
-
- pa_log_debug("Freeing the pa_volume_api object.");
-
- pa_assert(!api->mute_controls_from_db);
- pa_assert(!api->volume_controls_from_db);
-
- if (api->stream_creator)
- pa_stream_creator_free(api->stream_creator);
-
- if (api->device_creator)
- pa_device_creator_free(api->device_creator);
-
- if (api->create_objects_defer_event)
- api->core->mainloop->defer_free(api->create_objects_defer_event);
-
- delete_control_db(api);
-
- for (i = 0; i < PA_VOLUME_API_HOOK_MAX; i++)
- pa_hook_done(&api->hooks[i]);
-
- if (api->audio_groups) {
- pa_assert(pa_hashmap_isempty(api->audio_groups));
- pa_hashmap_free(api->audio_groups);
- }
-
- if (api->streams) {
- pa_assert(pa_hashmap_isempty(api->streams));
- pa_hashmap_free(api->streams);
- }
-
- if (api->devices) {
- pa_assert(pa_hashmap_isempty(api->devices));
- pa_hashmap_free(api->devices);
- }
-
- if (api->mute_controls) {
- pa_mute_control *control;
-
- while ((control = pa_hashmap_first(api->mute_controls))) {
- pa_assert(!control->present);
- pa_mute_control_free(control);
- }
-
- pa_hashmap_free(api->mute_controls);
- }
-
- if (api->volume_controls) {
- pa_volume_control *control;
-
- while ((control = pa_hashmap_first(api->volume_controls))) {
- pa_assert(!control->present);
- pa_volume_control_free(control);
- }
-
- pa_hashmap_free(api->volume_controls);
- }
-
- if (api->names) {
- pa_assert(pa_hashmap_isempty(api->names));
- pa_hashmap_free(api->names);
- }
-
- pa_xfree(api);
-}
-
-int pa_volume_api_register_name(pa_volume_api *api, const char *requested_name, bool fail_if_already_registered,
- const char **registered_name) {
- char *n;
-
- pa_assert(api);
- pa_assert(requested_name);
- pa_assert(registered_name);
-
- if (!pa_namereg_is_valid_name(requested_name)) {
- pa_log("Invalid name: \"%s\"", requested_name);
- return -PA_ERR_INVALID;
- }
-
- n = pa_xstrdup(requested_name);
-
- if (pa_hashmap_put(api->names, n, n) < 0) {
- unsigned i = 1;
-
- if (fail_if_already_registered) {
- pa_xfree(n);
- pa_log("Name %s already registered.", requested_name);
- return -PA_ERR_EXIST;
- }
-
- do {
- pa_xfree(n);
- i++;
- n = pa_sprintf_malloc("%s.%u", requested_name, i);
- } while (pa_hashmap_put(api->names, n, n) < 0);
- }
-
- *registered_name = n;
-
- return 0;
-}
-
-void pa_volume_api_unregister_name(pa_volume_api *api, const char *name) {
- pa_assert(api);
- pa_assert(name);
-
- pa_assert_se(pa_hashmap_remove_and_free(api->names, name) >= 0);
-}
-
-uint32_t pa_volume_api_allocate_volume_control_index(pa_volume_api *api) {
- uint32_t idx;
-
- pa_assert(api);
-
- idx = api->next_volume_control_index++;
-
- return idx;
-}
-
-void pa_volume_api_add_volume_control(pa_volume_api *api, pa_volume_control *control) {
- pa_assert(api);
- pa_assert(control);
-
- pa_assert_se(pa_hashmap_put(api->volume_controls, (void *) control->name, control) >= 0);
-}
-
-int pa_volume_api_remove_volume_control(pa_volume_api *api, pa_volume_control *control) {
- pa_assert(api);
- pa_assert(control);
-
- if (!pa_hashmap_remove(api->volume_controls, control->name))
- return -1;
-
- if (control == api->main_output_volume_control)
- pa_volume_api_set_main_output_volume_control(api, NULL);
-
- if (control == api->main_input_volume_control)
- pa_volume_api_set_main_input_volume_control(api, NULL);
-
- return 0;
-}
-
-pa_volume_control *pa_volume_api_get_volume_control_by_index(pa_volume_api *api, uint32_t idx) {
- pa_volume_control *control;
- void *state;
-
- pa_assert(api);
-
- PA_HASHMAP_FOREACH(control, api->volume_controls, state) {
- if (control->index == idx)
- return control;
- }
-
- return NULL;
-}
-
-uint32_t pa_volume_api_allocate_mute_control_index(pa_volume_api *api) {
- uint32_t idx;
-
- pa_assert(api);
-
- idx = api->next_mute_control_index++;
-
- return idx;
-}
-
-void pa_volume_api_add_mute_control(pa_volume_api *api, pa_mute_control *control) {
- pa_assert(api);
- pa_assert(control);
-
- pa_assert_se(pa_hashmap_put(api->mute_controls, (void *) control->name, control) >= 0);
-}
-
-int pa_volume_api_remove_mute_control(pa_volume_api *api, pa_mute_control *control) {
- pa_assert(api);
- pa_assert(control);
-
- if (!pa_hashmap_remove(api->mute_controls, control->name))
- return -1;
-
- if (control == api->main_output_mute_control)
- pa_volume_api_set_main_output_mute_control(api, NULL);
-
- if (control == api->main_input_mute_control)
- pa_volume_api_set_main_input_mute_control(api, NULL);
-
- return 0;
-}
-
-pa_mute_control *pa_volume_api_get_mute_control_by_index(pa_volume_api *api, uint32_t idx) {
- pa_mute_control *control;
- void *state;
-
- pa_assert(api);
-
- PA_HASHMAP_FOREACH(control, api->mute_controls, state) {
- if (control->index == idx)
- return control;
- }
-
- return NULL;
-}
-
-uint32_t pa_volume_api_allocate_device_index(pa_volume_api *api) {
- uint32_t idx;
-
- pa_assert(api);
-
- idx = api->next_device_index++;
-
- return idx;
-}
-
-void pa_volume_api_add_device(pa_volume_api *api, pa_device *device) {
- pa_assert(api);
- pa_assert(device);
-
- pa_assert_se(pa_hashmap_put(api->devices, (void *) device->name, device) >= 0);
-}
-
-int pa_volume_api_remove_device(pa_volume_api *api, pa_device *device) {
- pa_assert(api);
- pa_assert(device);
-
- if (!pa_hashmap_remove(api->devices, device->name))
- return -1;
-
- return 0;
-}
-
-pa_device *pa_volume_api_get_device_by_index(pa_volume_api *api, uint32_t idx) {
- pa_device *device;
- void *state;
-
- pa_assert(api);
-
- PA_HASHMAP_FOREACH(device, api->devices, state) {
- if (device->index == idx)
- return device;
- }
-
- return NULL;
-}
-
-uint32_t pa_volume_api_allocate_stream_index(pa_volume_api *api) {
- uint32_t idx;
-
- pa_assert(api);
-
- idx = api->next_stream_index++;
-
- return idx;
-}
-
-void pa_volume_api_add_stream(pa_volume_api *api, pas_stream *stream) {
- pa_assert(api);
- pa_assert(stream);
-
- pa_assert_se(pa_hashmap_put(api->streams, (void *) stream->name, stream) >= 0);
-}
-
-int pa_volume_api_remove_stream(pa_volume_api *api, pas_stream *stream) {
- pa_assert(api);
- pa_assert(stream);
-
- if (!pa_hashmap_remove(api->streams, stream->name))
- return -1;
-
- return 0;
-}
-
-pas_stream *pa_volume_api_get_stream_by_index(pa_volume_api *api, uint32_t idx) {
- pas_stream *stream;
- void *state;
-
- pa_assert(api);
-
- PA_HASHMAP_FOREACH(stream, api->streams, state) {
- if (stream->index == idx)
- return stream;
- }
-
- return NULL;
-}
-
-uint32_t pa_volume_api_allocate_audio_group_index(pa_volume_api *api) {
- uint32_t idx;
-
- pa_assert(api);
-
- idx = api->next_audio_group_index++;
-
- return idx;
-}
-
-void pa_volume_api_add_audio_group(pa_volume_api *api, pa_audio_group *group) {
- pa_assert(api);
- pa_assert(group);
-
- pa_assert_se(pa_hashmap_put(api->audio_groups, (void *) group->name, group) >= 0);
-}
-
-int pa_volume_api_remove_audio_group(pa_volume_api *api, pa_audio_group *group) {
- pa_assert(api);
- pa_assert(group);
-
- if (!pa_hashmap_remove(api->audio_groups, group->name))
- return -1;
-
- return 0;
-}
-
-pa_audio_group *pa_volume_api_get_audio_group_by_index(pa_volume_api *api, uint32_t idx) {
- pa_audio_group *group;
- void *state;
-
- pa_assert(api);
-
- PA_HASHMAP_FOREACH(group, api->audio_groups, state) {
- if (group->index == idx)
- return group;
- }
-
- return NULL;
-}
-
-void pa_volume_api_set_main_output_volume_control(pa_volume_api *api, pa_volume_control *control) {
- pa_volume_control *old_control;
-
- pa_assert(api);
-
- old_control = api->main_output_volume_control;
-
- if (control == old_control)
- return;
-
- api->main_output_volume_control = control;
-
- pa_log_debug("Main output volume control changed from %s to %s.", old_control ? old_control->name : "(unset)",
- control ? control->name : "(unset)");
-
- pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED], api);
-}
-
-void pa_volume_api_set_main_input_volume_control(pa_volume_api *api, pa_volume_control *control) {
- pa_volume_control *old_control;
-
- pa_assert(api);
-
- old_control = api->main_input_volume_control;
-
- if (control == old_control)
- return;
-
- api->main_input_volume_control = control;
-
- pa_log_debug("Main input volume control changed from %s to %s.", old_control ? old_control->name : "(unset)",
- control ? control->name : "(unset)");
-
- pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_INPUT_VOLUME_CONTROL_CHANGED], api);
-}
-
-void pa_volume_api_set_main_output_mute_control(pa_volume_api *api, pa_mute_control *control) {
- pa_mute_control *old_control;
-
- pa_assert(api);
-
- old_control = api->main_output_mute_control;
-
- if (control == old_control)
- return;
-
- api->main_output_mute_control = control;
-
- pa_log_debug("Main output mute control changed from %s to %s.", old_control ? old_control->name : "(unset)",
- control ? control->name : "(unset)");
-
- pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_OUTPUT_MUTE_CONTROL_CHANGED], api);
-}
-
-void pa_volume_api_set_main_input_mute_control(pa_volume_api *api, pa_mute_control *control) {
- pa_mute_control *old_control;
-
- pa_assert(api);
-
- old_control = api->main_input_mute_control;
-
- if (control == old_control)
- return;
-
- api->main_input_mute_control = control;
-
- pa_log_debug("Main input mute control changed from %s to %s.", old_control ? old_control->name : "(unset)",
- control ? control->name : "(unset)");
-
- pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_INPUT_MUTE_CONTROL_CHANGED], api);
-}
+++ /dev/null
-#ifndef foovolumeapihfoo
-#define foovolumeapihfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <pulsecore/core.h>
-
-#define PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_DESCRIPTION "description"
-#define PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_VOLUME "volume"
-#define PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_BALANCE "balance"
-#define PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_CONVERTIBLE_TO_DB "convertible-to-dB"
-#define PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_MUTE "mute"
-
-typedef struct pa_volume_api pa_volume_api;
-
-/* Avoid circular dependencies... */
-typedef struct pa_audio_group pa_audio_group;
-typedef struct pa_device pa_device;
-typedef struct pa_device_creator pa_device_creator;
-typedef struct pa_inidb pa_inidb;
-typedef struct pa_inidb_table pa_inidb_table;
-typedef struct pa_mute_control pa_mute_control;
-typedef struct pas_stream pas_stream;
-typedef struct pa_stream_creator pa_stream_creator;
-typedef struct pa_volume_control pa_volume_control;
-
-enum {
- /* This is fired after the volume control implementation has done its part
- * of the volume control initialization, but before policy modules have
- * done their part of the initialization. Hook users are expected to not
- * modify the volume control state in this hook. */
- PA_VOLUME_API_HOOK_VOLUME_CONTROL_IMPLEMENTATION_INITIALIZED,
-
- /* Policy modules can use this hook to initialize the volume control
- * volume. This is fired before PUT. If a policy module sets the volume, it
- * should return PA_HOOK_STOP to prevent lower-priority policy modules from
- * modifying the volume. */
- PA_VOLUME_API_HOOK_VOLUME_CONTROL_SET_INITIAL_VOLUME,
-
- PA_VOLUME_API_HOOK_VOLUME_CONTROL_PUT,
- PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK,
- PA_VOLUME_API_HOOK_VOLUME_CONTROL_DESCRIPTION_CHANGED,
- PA_VOLUME_API_HOOK_VOLUME_CONTROL_VOLUME_CHANGED,
- PA_VOLUME_API_HOOK_VOLUME_CONTROL_CONVERTIBLE_TO_DB_CHANGED,
-
- /* This is fired after the mute control implementation has done its part of
- * the mute control initialization, but before policy modules have done
- * their part of the initialization. Hook users are expected to not modify
- * the mute control state in this hook. */
- PA_VOLUME_API_HOOK_MUTE_CONTROL_IMPLEMENTATION_INITIALIZED,
-
- /* Policy modules can use this hook to initialize the mute control mute.
- * This is fired before PUT. If a policy module sets the mute, it should
- * return PA_HOOK_STOP to prevent lower-priority policy modules from
- * modifying the mute. */
- PA_VOLUME_API_HOOK_MUTE_CONTROL_SET_INITIAL_MUTE,
-
- PA_VOLUME_API_HOOK_MUTE_CONTROL_PUT,
- PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK,
- PA_VOLUME_API_HOOK_MUTE_CONTROL_DESCRIPTION_CHANGED,
- PA_VOLUME_API_HOOK_MUTE_CONTROL_MUTE_CHANGED,
- PA_VOLUME_API_HOOK_DEVICE_PUT,
- PA_VOLUME_API_HOOK_DEVICE_UNLINK,
- PA_VOLUME_API_HOOK_DEVICE_DESCRIPTION_CHANGED,
- PA_VOLUME_API_HOOK_DEVICE_VOLUME_CONTROL_CHANGED,
- PA_VOLUME_API_HOOK_DEVICE_MUTE_CONTROL_CHANGED,
- PA_VOLUME_API_HOOK_STREAM_PUT,
- PA_VOLUME_API_HOOK_STREAM_UNLINK,
- PA_VOLUME_API_HOOK_STREAM_DESCRIPTION_CHANGED,
- PA_VOLUME_API_HOOK_STREAM_PROPLIST_CHANGED,
- PA_VOLUME_API_HOOK_STREAM_VOLUME_CONTROL_CHANGED,
- PA_VOLUME_API_HOOK_STREAM_RELATIVE_VOLUME_CONTROL_CHANGED,
- PA_VOLUME_API_HOOK_STREAM_MUTE_CONTROL_CHANGED,
- PA_VOLUME_API_HOOK_AUDIO_GROUP_PUT,
- PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK,
- PA_VOLUME_API_HOOK_AUDIO_GROUP_DESCRIPTION_CHANGED,
- PA_VOLUME_API_HOOK_AUDIO_GROUP_VOLUME_CONTROL_CHANGED,
- PA_VOLUME_API_HOOK_AUDIO_GROUP_MUTE_CONTROL_CHANGED,
- PA_VOLUME_API_HOOK_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED,
- PA_VOLUME_API_HOOK_MAIN_INPUT_VOLUME_CONTROL_CHANGED,
- PA_VOLUME_API_HOOK_MAIN_OUTPUT_MUTE_CONTROL_CHANGED,
- PA_VOLUME_API_HOOK_MAIN_INPUT_MUTE_CONTROL_CHANGED,
- PA_VOLUME_API_HOOK_MAX
-};
-
-struct pa_volume_api {
- pa_core *core;
- unsigned refcnt;
- pa_hashmap *names; /* object name -> object name (hashmap-as-a-set) */
- pa_hashmap *volume_controls; /* name -> pa_volume_control */
- pa_hashmap *mute_controls; /* name -> pa_mute_control */
- pa_hashmap *devices; /* name -> pa_device */
- pa_hashmap *streams; /* name -> pas_stream */
- pa_hashmap *audio_groups; /* name -> pa_audio_group */
- pa_volume_control *main_output_volume_control;
- pa_volume_control *main_input_volume_control;
- pa_mute_control *main_output_mute_control;
- pa_mute_control *main_input_mute_control;
-
- uint32_t next_volume_control_index;
- uint32_t next_mute_control_index;
- uint32_t next_device_index;
- uint32_t next_stream_index;
- uint32_t next_audio_group_index;
- pa_hook hooks[PA_VOLUME_API_HOOK_MAX];
-
- struct {
- pa_inidb *db;
- pa_inidb_table *volume_controls;
- pa_inidb_table *mute_controls;
- } control_db;
-
- pa_defer_event *create_objects_defer_event;
- pa_device_creator *device_creator;
- pa_stream_creator *stream_creator;
-
- pa_hashmap *volume_controls_from_db; /* control name -> pa_volume_control, only used during initialization. */
- pa_hashmap *mute_controls_from_db; /* control name -> pa_mute_control, only used during initialization. */
-};
-
-pa_volume_api *pa_volume_api_get(pa_core *core);
-pa_volume_api *pa_volume_api_ref(pa_volume_api *api);
-void pa_volume_api_unref(pa_volume_api *api);
-
-int pa_volume_api_register_name(pa_volume_api *api, const char *requested_name, bool fail_if_already_registered,
- const char **registered_name);
-void pa_volume_api_unregister_name(pa_volume_api *api, const char *name);
-
-uint32_t pa_volume_api_allocate_volume_control_index(pa_volume_api *api);
-void pa_volume_api_add_volume_control(pa_volume_api *api, pa_volume_control *control);
-int pa_volume_api_remove_volume_control(pa_volume_api *api, pa_volume_control *control);
-pa_volume_control *pa_volume_api_get_volume_control_by_index(pa_volume_api *api, uint32_t idx);
-
-uint32_t pa_volume_api_allocate_mute_control_index(pa_volume_api *api);
-void pa_volume_api_add_mute_control(pa_volume_api *api, pa_mute_control *control);
-int pa_volume_api_remove_mute_control(pa_volume_api *api, pa_mute_control *control);
-pa_mute_control *pa_volume_api_get_mute_control_by_index(pa_volume_api *api, uint32_t idx);
-
-uint32_t pa_volume_api_allocate_device_index(pa_volume_api *api);
-void pa_volume_api_add_device(pa_volume_api *api, pa_device *device);
-int pa_volume_api_remove_device(pa_volume_api *api, pa_device *device);
-pa_device *pa_volume_api_get_device_by_index(pa_volume_api *api, uint32_t idx);
-
-uint32_t pa_volume_api_allocate_stream_index(pa_volume_api *api);
-void pa_volume_api_add_stream(pa_volume_api *api, pas_stream *stream);
-int pa_volume_api_remove_stream(pa_volume_api *api, pas_stream *stream);
-pas_stream *pa_volume_api_get_stream_by_index(pa_volume_api *api, uint32_t idx);
-
-uint32_t pa_volume_api_allocate_audio_group_index(pa_volume_api *api);
-void pa_volume_api_add_audio_group(pa_volume_api *api, pa_audio_group *group);
-int pa_volume_api_remove_audio_group(pa_volume_api *api, pa_audio_group *group);
-pa_audio_group *pa_volume_api_get_audio_group_by_index(pa_volume_api *api, uint32_t idx);
-
-void pa_volume_api_set_main_output_volume_control(pa_volume_api *api, pa_volume_control *control);
-void pa_volume_api_set_main_input_volume_control(pa_volume_api *api, pa_volume_control *control);
-void pa_volume_api_set_main_output_mute_control(pa_volume_api *api, pa_mute_control *control);
-void pa_volume_api_set_main_input_mute_control(pa_volume_api *api, pa_mute_control *control);
-
-#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "volume-control.h"
-
-#include <modules/volume-api/audio-group.h>
-#include <modules/volume-api/device.h>
-#include <modules/volume-api/inidb.h>
-#include <modules/volume-api/sstream.h>
-
-#include <pulsecore/core-util.h>
-
-int pa_volume_control_new(pa_volume_api *api, const char *name, bool persistent, pa_volume_control **_r) {
- pa_volume_control *control = NULL;
- int r;
-
- pa_assert(api);
- pa_assert(name);
- pa_assert(_r);
-
- control = pa_xnew0(pa_volume_control, 1);
- control->volume_api = api;
- control->index = pa_volume_api_allocate_volume_control_index(api);
-
- r = pa_volume_api_register_name(api, name, persistent, &control->name);
- if (r < 0)
- goto fail;
-
- control->description = pa_xstrdup(control->name);
- control->proplist = pa_proplist_new();
- pa_bvolume_init_mono(&control->volume, PA_VOLUME_NORM);
- control->present = !persistent;
- control->persistent = persistent;
- control->purpose = PA_VOLUME_CONTROL_PURPOSE_OTHER;
- control->devices = pa_hashmap_new(NULL, NULL);
- control->default_for_devices = pa_hashmap_new(NULL, NULL);
-
- if (persistent) {
- pa_inidb_row *row;
-
- row = pa_inidb_table_add_row(api->control_db.volume_controls, control->name);
- control->db_cells.description = pa_inidb_row_get_cell(row, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_DESCRIPTION);
- control->db_cells.volume = pa_inidb_row_get_cell(row, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_VOLUME);
- control->db_cells.balance = pa_inidb_row_get_cell(row, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_BALANCE);
- control->db_cells.convertible_to_dB = pa_inidb_row_get_cell(row,
- PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_CONVERTIBLE_TO_DB);
- }
-
- *_r = control;
- return 0;
-
-fail:
- if (control)
- pa_volume_control_free(control);
-
- return r;
-}
-
-void pa_volume_control_put(pa_volume_control *control) {
- const char *prop_key;
- void *state = NULL;
- char volume_str[PA_VOLUME_SNPRINT_VERBOSE_MAX];
- char balance_str[PA_BVOLUME_SNPRINT_BALANCE_MAX];
-
- pa_assert(control);
- pa_assert(control->set_volume || !control->present);
-
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_IMPLEMENTATION_INITIALIZED], control);
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_SET_INITIAL_VOLUME], control);
-
- if (control->set_volume) {
- control->set_volume_in_progress = true;
- control->set_volume(control, &control->volume, &control->volume, true, true);
- control->set_volume_in_progress = false;
- }
-
- pa_volume_api_add_volume_control(control->volume_api, control);
- control->linked = true;
-
- pa_log_debug("Created volume control #%u.", control->index);
- pa_log_debug(" Name: %s", control->name);
- pa_log_debug(" Description: %s", control->description);
- pa_log_debug(" Volume: %s", pa_volume_snprint_verbose(volume_str, sizeof(volume_str), control->volume.volume,
- control->convertible_to_dB));
- pa_log_debug(" Balance: %s", pa_bvolume_snprint_balance(balance_str, sizeof(balance_str), &control->volume));
- pa_log_debug(" Present: %s", pa_yes_no(control->present));
- pa_log_debug(" Persistent: %s", pa_yes_no(control->persistent));
- pa_log_debug(" Properties:");
-
- while ((prop_key = pa_proplist_iterate(control->proplist, &state)))
- pa_log_debug(" %s = %s", prop_key, pa_strnull(pa_proplist_gets(control->proplist, prop_key)));
-
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_PUT], control);
-}
-
-void pa_volume_control_unlink(pa_volume_control *control) {
- pa_device *device;
-
- pa_assert(control);
-
- if (control->unlinked) {
- pa_log_debug("Unlinking volume control %s (already unlinked, this is a no-op).", control->name);
- return;
- }
-
- control->unlinked = true;
-
- pa_log_debug("Unlinking volume control %s.", control->name);
-
- if (control->linked)
- pa_volume_api_remove_volume_control(control->volume_api, control);
-
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK], control);
-
- while ((device = pa_hashmap_first(control->default_for_devices)))
- pa_device_set_default_volume_control(device, NULL);
-
- while ((device = pa_hashmap_first(control->devices))) {
- /* Why do we have this assertion here? The concern is that if we call
- * pa_device_set_volume_control() for some device that has the
- * use_default_volume_control flag set, then that flag will be unset as
- * a side effect, and we don't want that side effect. This assertion
- * should be safe, because we just called
- * pa_device_set_default_volume_control(NULL) for each device that this
- * control was the default for, and that should ensure that we don't
- * any more hold any references to devices that used to use this
- * control as the default. */
- pa_assert(!device->use_default_volume_control);
- pa_device_set_volume_control(device, NULL);
- }
-}
-
-void pa_volume_control_free(pa_volume_control *control) {
- pa_assert(control);
-
- /* unlink() expects name to be set. */
- if (!control->unlinked && control->name)
- pa_volume_control_unlink(control);
-
- if (control->default_for_devices) {
- pa_assert(pa_hashmap_isempty(control->default_for_devices));
- pa_hashmap_free(control->default_for_devices);
- }
-
- if (control->devices) {
- pa_assert(pa_hashmap_isempty(control->devices));
- pa_hashmap_free(control->devices);
- }
-
- if (control->proplist)
- pa_proplist_free(control->proplist);
-
- pa_xfree(control->description);
-
- if (control->name)
- pa_volume_api_unregister_name(control->volume_api, control->name);
-
- pa_xfree(control);
-}
-
-void pa_volume_control_set_purpose(pa_volume_control *control, pa_volume_control_purpose_t purpose, void *owner) {
- pa_assert(control);
- pa_assert(!control->linked);
-
- control->purpose = purpose;
- control->owner = owner;
-}
-
-int pa_volume_control_acquire_for_audio_group(pa_volume_control *control, pa_audio_group *group,
- pa_volume_control_set_volume_cb_t set_volume_cb, void *userdata) {
- pa_assert(control);
- pa_assert(group);
- pa_assert(set_volume_cb);
-
- if (control->present) {
- pa_log("Can't acquire volume control %s, it's already present.", control->name);
- return -PA_ERR_BUSY;
- }
-
- control->set_volume = set_volume_cb;
- control->userdata = userdata;
-
- control->set_volume_in_progress = true;
- control->set_volume(control, &control->volume, &control->volume, true, true);
- control->set_volume_in_progress = false;
-
- control->present = true;
-
- if (!control->linked || control->unlinked)
- return 0;
-
- pa_log_debug("Volume control %s became present.", control->name);
-
- return 0;
-}
-
-void pa_volume_control_release(pa_volume_control *control) {
- pa_assert(control);
-
- if (!control->present)
- return;
-
- control->present = false;
-
- control->userdata = NULL;
- control->set_volume = NULL;
-
- if (!control->linked || control->unlinked)
- return;
-
- pa_log_debug("Volume control %s became not present.", control->name);
-}
-
-void pa_volume_control_set_description(pa_volume_control *control, const char *description) {
- char *old_description;
-
- pa_assert(control);
- pa_assert(description);
-
- old_description = control->description;
-
- if (pa_streq(description, old_description))
- return;
-
- control->description = pa_xstrdup(description);
-
- if (control->persistent)
- pa_inidb_cell_set_value(control->db_cells.description, description);
-
- if (!control->linked || control->unlinked) {
- pa_xfree(old_description);
- return;
- }
-
- pa_log_debug("The description of volume control %s changed from \"%s\" to \"%s\".", control->name, old_description,
- description);
- pa_xfree(old_description);
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_DESCRIPTION_CHANGED], control);
-}
-
-static void set_volume_internal(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance) {
- pa_bvolume old_volume;
- bool volume_changed;
- bool balance_changed;
- char *str;
-
- pa_assert(control);
- pa_assert(volume);
-
- old_volume = control->volume;
- volume_changed = !pa_bvolume_equal(volume, &old_volume, set_volume, false);
- balance_changed = !pa_bvolume_equal(volume, &old_volume, false, set_balance);
-
- if (!volume_changed && !balance_changed)
- return;
-
- if (volume_changed) {
- control->volume.volume = volume->volume;
-
- if (control->persistent) {
- str = pa_sprintf_malloc("%u", control->volume.volume);
- pa_inidb_cell_set_value(control->db_cells.volume, str);
- pa_xfree(str);
- }
- }
-
- if (balance_changed) {
- pa_bvolume_copy_balance(&control->volume, volume);
-
- if (control->persistent) {
- pa_assert_se(pa_bvolume_balance_to_string(&control->volume, &str) >= 0);
- pa_inidb_cell_set_value(control->db_cells.balance, str);
- pa_xfree(str);
- }
- }
-
- if (!control->linked || control->unlinked)
- return;
-
- if (volume_changed) {
- char old_volume_str[PA_VOLUME_SNPRINT_VERBOSE_MAX];
- char new_volume_str[PA_VOLUME_SNPRINT_VERBOSE_MAX];
-
- pa_log_debug("The volume of volume control %s changed from %s to %s.", control->name,
- pa_volume_snprint_verbose(old_volume_str, sizeof(old_volume_str), old_volume.volume,
- control->convertible_to_dB),
- pa_volume_snprint_verbose(new_volume_str, sizeof(new_volume_str), control->volume.volume,
- control->convertible_to_dB));
- }
-
- if (balance_changed) {
- char old_balance_str[PA_BVOLUME_SNPRINT_BALANCE_MAX];
- char new_balance_str[PA_BVOLUME_SNPRINT_BALANCE_MAX];
-
- pa_log_debug("The balance of volume control %s changed from %s to %s.", control->name,
- pa_bvolume_snprint_balance(old_balance_str, sizeof(old_balance_str), &control->volume),
- pa_bvolume_snprint_balance(new_balance_str, sizeof(new_balance_str), &control->volume));
- }
-
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_VOLUME_CHANGED], control);
-}
-
-int pa_volume_control_set_volume(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance) {
- pa_bvolume volume_local;
- int r;
-
- pa_assert(control);
- pa_assert(volume);
-
- if (control->set_volume_in_progress)
- return 0;
-
- volume_local = *volume;
-
- if (set_balance && !pa_channel_map_equal(&volume_local.channel_map, &control->volume.channel_map))
- pa_bvolume_remap(&volume_local, &control->volume.channel_map);
-
- if (pa_bvolume_equal(&volume_local, &control->volume, set_volume, set_balance))
- return 0;
-
- if (control->linked && control->present) {
- control->set_volume_in_progress = true;
- r = control->set_volume(control, volume, &volume_local, set_volume, set_balance);
- control->set_volume_in_progress = false;
-
- if (r < 0) {
- pa_log("Setting the volume of volume control %s failed.", control->name);
- return r;
- }
- }
-
- set_volume_internal(control, &volume_local, set_volume, set_balance);
-
- return 0;
-}
-
-void pa_volume_control_set_channel_map(pa_volume_control *control, const pa_channel_map *map) {
- pa_bvolume bvolume;
-
- pa_assert(control);
- pa_assert(map);
-
- if (pa_channel_map_equal(map, &control->volume.channel_map))
- return;
-
- pa_bvolume_copy_balance(&bvolume, &control->volume);
- pa_bvolume_remap(&bvolume, map);
-
- set_volume_internal(control, &bvolume, false, true);
-}
-
-void pa_volume_control_set_convertible_to_dB(pa_volume_control *control, bool convertible) {
- bool old_convertible;
-
- pa_assert(control);
-
- old_convertible = control->convertible_to_dB;
-
- if (convertible == old_convertible)
- return;
-
- control->convertible_to_dB = convertible;
-
- if (control->persistent)
- pa_inidb_cell_set_value(control->db_cells.convertible_to_dB, pa_boolean_to_string(convertible));
-
- if (!control->linked || control->unlinked)
- return;
-
- pa_log_debug("The volume of volume control %s became %sconvertible to dB.", control->name, convertible ? "" : "not ");
-
- pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_CONVERTIBLE_TO_DB_CHANGED], control);
-}
-
-void pa_volume_control_add_device(pa_volume_control *control, pa_device *device) {
- pa_assert(control);
- pa_assert(device);
-
- pa_assert_se(pa_hashmap_put(control->devices, device, device) >= 0);
-}
-
-void pa_volume_control_remove_device(pa_volume_control *control, pa_device *device) {
- pa_assert(control);
- pa_assert(device);
-
- pa_assert_se(pa_hashmap_remove(control->devices, device));
-}
-
-void pa_volume_control_add_default_for_device(pa_volume_control *control, pa_device *device) {
- pa_assert(control);
- pa_assert(device);
-
- pa_assert_se(pa_hashmap_put(control->default_for_devices, device, device) >= 0);
-}
-
-void pa_volume_control_remove_default_for_device(pa_volume_control *control, pa_device *device) {
- pa_assert(control);
- pa_assert(device);
-
- pa_assert_se(pa_hashmap_remove(control->default_for_devices, device));
-}
+++ /dev/null
-#ifndef foovolumecontrolhfoo
-#define foovolumecontrolhfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <modules/volume-api/bvolume.h>
-#include <modules/volume-api/inidb.h>
-#include <modules/volume-api/volume-api.h>
-
-typedef struct pa_volume_control pa_volume_control;
-
-typedef enum {
- PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME,
- PA_VOLUME_CONTROL_PURPOSE_OTHER,
-} pa_volume_control_purpose_t;
-
-/* Usually remapped_volume is the volume to use, because it has a matching
- * channel map with the control, but in case the volume needs to be propagated
- * to another control, original_volume can be used to avoid loss of precision
- * that can result from remapping. */
-typedef int (*pa_volume_control_set_volume_cb_t)(pa_volume_control *control, const pa_bvolume *original_volume,
- const pa_bvolume *remapped_volume, bool set_volume, bool set_balance);
-
-struct pa_volume_control {
- pa_volume_api *volume_api;
- uint32_t index;
- const char *name;
- char *description;
- pa_proplist *proplist;
- pa_bvolume volume;
- bool convertible_to_dB;
- bool present;
- bool persistent;
-
- pa_volume_control_purpose_t purpose;
- union {
- pas_stream *owner_stream;
- void *owner;
- };
-
- pa_hashmap *devices; /* pa_device -> pa_device (hashmap-as-a-set) */
- pa_hashmap *default_for_devices; /* pa_device -> pa_device (hashmap-as-a-set) */
-
- struct {
- pa_inidb_cell *description;
- pa_inidb_cell *volume;
- pa_inidb_cell *balance;
- pa_inidb_cell *convertible_to_dB;
- } db_cells;
-
- bool linked;
- bool unlinked;
- bool set_volume_in_progress;
-
- /* Called from pa_volume_control_set_volume(). The implementation is
- * expected to return a negative error code on failure. */
- pa_volume_control_set_volume_cb_t set_volume;
-
- void *userdata;
-};
-
-int pa_volume_control_new(pa_volume_api *api, const char *name, bool persistent, pa_volume_control **_r);
-void pa_volume_control_put(pa_volume_control *control);
-void pa_volume_control_unlink(pa_volume_control *control);
-void pa_volume_control_free(pa_volume_control *control);
-
-/* Called by the volume control implementation, before
- * pa_volume_control_put(). */
-void pa_volume_control_set_purpose(pa_volume_control *control, pa_volume_control_purpose_t purpose, void *owner);
-
-/* Called by the volume control implementation. */
-int pa_volume_control_acquire_for_audio_group(pa_volume_control *control, pa_audio_group *group,
- pa_volume_control_set_volume_cb_t set_volume_cb, void *userdata);
-
-/* Called by the volume control implementation. This must only be called for
- * persistent controls; use pa_volume_control_free() for non-persistent
- * controls. */
-void pa_volume_control_release(pa_volume_control *control);
-
-/* Called by anyone. */
-void pa_volume_control_set_description(pa_volume_control *control, const char *description);
-int pa_volume_control_set_volume(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance);
-
-/* Called by the volume control implementation. */
-void pa_volume_control_set_channel_map(pa_volume_control *control, const pa_channel_map *map);
-void pa_volume_control_set_convertible_to_dB(pa_volume_control *control, bool convertible);
-
-/* Called from device.c only. */
-void pa_volume_control_add_device(pa_volume_control *control, pa_device *device);
-void pa_volume_control_remove_device(pa_volume_control *control, pa_device *device);
-void pa_volume_control_add_default_for_device(pa_volume_control *control, pa_device *device);
-void pa_volume_control_remove_default_for_device(pa_volume_control *control, pa_device *device);
-
-#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "ext-volume-api.h"
-
-#include <modules/volume-api/volume-api-common.h>
-
-#include <pulse/direction.h>
-#include <pulse/extension.h>
-#include <pulse/internal.h>
-#include <pulse/xmalloc.h>
-
-#include <pulsecore/core-util.h>
-#include <pulsecore/i18n.h>
-#include <pulsecore/macro.h>
-#include <pulsecore/pstream-util.h>
-#include <pulsecore/strbuf.h>
-
-#include <math.h>
-
-struct userdata {
- pa_extension *extension;
- pa_context *context;
- pa_ext_volume_api_state_t state;
- bool state_notification_needed;
- pa_ext_volume_api_state_cb_t state_callback;
- void *state_callback_userdata;
- pa_ext_volume_api_subscription_mask_t subscription_mask;
- pa_ext_volume_api_subscribe_cb_t subscribe_callback;
- void *subscribe_callback_userdata;
-};
-
-static struct userdata *get_userdata(pa_context *context, bool create);
-static void userdata_free(struct userdata *u);
-static void set_state(struct userdata *u, pa_ext_volume_api_state_t state, bool notify);
-
-int pa_ext_volume_api_balance_valid(double balance) {
- return balance >= 0.0 && balance <= 1.0;
-}
-
-int pa_ext_volume_api_bvolume_valid(const pa_ext_volume_api_bvolume *volume, int check_volume, int check_balance) {
- unsigned channel;
-
- pa_assert(volume);
-
- if (check_volume && !PA_VOLUME_IS_VALID(volume->volume))
- return 0;
-
- if (!check_balance)
- return 1;
-
- if (!pa_channel_map_valid(&volume->channel_map))
- return 0;
-
- for (channel = 0; channel < volume->channel_map.channels; channel++) {
- if (!pa_ext_volume_api_balance_valid(volume->balance[channel]))
- return 0;
- }
-
- return 1;
-}
-
-void pa_ext_volume_api_bvolume_init_invalid(pa_ext_volume_api_bvolume *volume) {
- unsigned i;
-
- pa_assert(volume);
-
- volume->volume = PA_VOLUME_INVALID;
-
- for (i = 0; i < PA_CHANNELS_MAX; i++)
- volume->balance[i] = -1.0;
-
- pa_channel_map_init(&volume->channel_map);
-}
-
-void pa_ext_volume_api_bvolume_init(pa_ext_volume_api_bvolume *bvolume, pa_volume_t volume, pa_channel_map *map) {
- unsigned i;
-
- pa_assert(bvolume);
- pa_assert(PA_VOLUME_IS_VALID(volume));
- pa_assert(map);
- pa_assert(pa_channel_map_valid(map));
-
- bvolume->volume = volume;
- bvolume->channel_map = *map;
-
- for (i = 0; i < map->channels; i++)
- bvolume->balance[i] = 1.0;
-}
-
-void pa_ext_volume_api_bvolume_init_mono(pa_ext_volume_api_bvolume *bvolume, pa_volume_t volume) {
- pa_assert(bvolume);
- pa_assert(PA_VOLUME_IS_VALID(volume));
-
- bvolume->volume = volume;
- bvolume->balance[0] = 1.0;
- pa_channel_map_init_mono(&bvolume->channel_map);
-}
-
-int pa_ext_volume_api_bvolume_parse_balance(const char *str, pa_ext_volume_api_bvolume *_r) {
- pa_ext_volume_api_bvolume bvolume;
-
- pa_assert(str);
- pa_assert(_r);
-
- bvolume.channel_map.channels = 0;
-
- for (;;) {
- const char *colon;
- size_t channel_name_len;
- char *channel_name;
- pa_channel_position_t position;
- const char *space;
- size_t balance_str_len;
- char *balance_str;
- int r;
- double balance;
-
- colon = strchr(str, ':');
- if (!colon)
- return -PA_ERR_INVALID;
-
- channel_name_len = colon - str;
- channel_name = pa_xstrndup(str, channel_name_len);
-
- position = pa_channel_position_from_string(channel_name);
- pa_xfree(channel_name);
- if (position == PA_CHANNEL_POSITION_INVALID)
- return -PA_ERR_INVALID;
-
- bvolume.channel_map.map[bvolume.channel_map.channels] = position;
- str = colon + 1;
-
- space = strchr(str, ' ');
- if (space)
- balance_str_len = space - str;
- else
- balance_str_len = strlen(str);
-
- balance_str = pa_xstrndup(str, balance_str_len);
-
- r = pa_atod(balance_str, &balance);
- if (r < 0)
- return -PA_ERR_INVALID;
-
- if (!pa_ext_volume_api_balance_valid(balance))
- return -PA_ERR_INVALID;
-
- bvolume.balance[bvolume.channel_map.channels++] = balance;
-
- if (space)
- str = space + 1;
- else
- break;
- }
-
- pa_ext_volume_api_bvolume_copy_balance(_r, &bvolume);
- return 0;
-}
-
-int pa_ext_volume_api_bvolume_equal(const pa_ext_volume_api_bvolume *a, const pa_ext_volume_api_bvolume *b,
- int check_volume, int check_balance) {
- unsigned i;
-
- pa_assert(a);
- pa_assert(b);
-
- if (check_volume && a->volume != b->volume)
- return 0;
-
- if (!check_balance)
- return 1;
-
- if (!pa_channel_map_equal(&a->channel_map, &b->channel_map))
- return 0;
-
- for (i = 0; i < a->channel_map.channels; i++) {
- if (fabs(a->balance[i] - b->balance[i]) > 0.00001)
- return 0;
- }
-
- return 1;
-}
-
-void pa_ext_volume_api_bvolume_from_cvolume(pa_ext_volume_api_bvolume *bvolume, const pa_cvolume *cvolume,
- const pa_channel_map *map) {
- unsigned i;
-
- pa_assert(bvolume);
- pa_assert(cvolume);
- pa_assert(map);
- pa_assert(cvolume->channels == map->channels);
-
- bvolume->volume = pa_cvolume_max(cvolume);
- bvolume->channel_map = *map;
-
- for (i = 0; i < map->channels; i++) {
- if (bvolume->volume != PA_VOLUME_MUTED)
- bvolume->balance[i] = ((double) cvolume->values[i]) / ((double) bvolume->volume);
- else
- bvolume->balance[i] = 1.0;
- }
-}
-
-void pa_ext_volume_api_bvolume_to_cvolume(const pa_ext_volume_api_bvolume *bvolume, pa_cvolume *cvolume) {
- unsigned i;
-
- pa_assert(bvolume);
- pa_assert(cvolume);
- pa_assert(pa_ext_volume_api_bvolume_valid(bvolume, true, true));
-
- cvolume->channels = bvolume->channel_map.channels;
-
- for (i = 0; i < bvolume->channel_map.channels; i++)
- cvolume->values[i] = bvolume->volume * bvolume->balance[i];
-}
-
-void pa_ext_volume_api_bvolume_copy_balance(pa_ext_volume_api_bvolume *to,
- const pa_ext_volume_api_bvolume *from) {
- pa_assert(to);
- pa_assert(from);
-
- memcpy(to->balance, from->balance, sizeof(from->balance));
- to->channel_map = from->channel_map;
-}
-
-void pa_ext_volume_api_bvolume_reset_balance(pa_ext_volume_api_bvolume *volume, const pa_channel_map *map) {
- unsigned i;
-
- pa_assert(volume);
- pa_assert(map);
- pa_assert(pa_channel_map_valid(map));
-
- for (i = 0; i < map->channels; i++)
- volume->balance[i] = 1.0;
-
- volume->channel_map = *map;
-}
-
-void pa_ext_volume_api_bvolume_remap(pa_ext_volume_api_bvolume *volume, const pa_channel_map *to) {
- unsigned i;
- pa_cvolume cvolume;
-
- pa_assert(volume);
- pa_assert(to);
- pa_assert(pa_ext_volume_api_bvolume_valid(volume, false, true));
- pa_assert(pa_channel_map_valid(to));
-
- cvolume.channels = volume->channel_map.channels;
-
- for (i = 0; i < cvolume.channels; i++)
- cvolume.values[i] = volume->balance[i] * (double) PA_VOLUME_NORM;
-
- pa_cvolume_remap(&cvolume, &volume->channel_map, to);
-
- for (i = 0; i < to->channels; i++)
- volume->balance[i] = (double) cvolume.values[i] / (double) PA_VOLUME_NORM;
-
- volume->channel_map = *to;
-}
-
-double pa_ext_volume_api_bvolume_get_left_right_balance(const pa_ext_volume_api_bvolume *volume) {
- pa_ext_volume_api_bvolume bvolume;
- pa_cvolume cvolume;
- double ret;
-
- pa_assert(volume);
-
- bvolume.volume = PA_VOLUME_NORM;
- pa_ext_volume_api_bvolume_copy_balance(&bvolume, volume);
- pa_ext_volume_api_bvolume_to_cvolume(&bvolume, &cvolume);
- ret = pa_cvolume_get_balance(&cvolume, &volume->channel_map);
-
- return ret;
-}
-
-void pa_ext_volume_api_bvolume_set_left_right_balance(pa_ext_volume_api_bvolume *volume, double balance) {
- pa_cvolume cvolume;
- pa_volume_t old_volume;
-
- pa_assert(volume);
-
- if (!pa_channel_map_can_balance(&volume->channel_map))
- return;
-
- pa_cvolume_reset(&cvolume, volume->channel_map.channels);
- pa_cvolume_set_balance(&cvolume, &volume->channel_map, balance);
- old_volume = volume->volume;
- pa_ext_volume_api_bvolume_from_cvolume(volume, &cvolume, &volume->channel_map);
- volume->volume = old_volume;
-}
-
-double pa_ext_volume_api_bvolume_get_rear_front_balance(const pa_ext_volume_api_bvolume *volume) {
- pa_ext_volume_api_bvolume bvolume;
- pa_cvolume cvolume;
- double ret;
-
- pa_assert(volume);
-
- bvolume.volume = PA_VOLUME_NORM;
- pa_ext_volume_api_bvolume_copy_balance(&bvolume, volume);
- pa_ext_volume_api_bvolume_to_cvolume(&bvolume, &cvolume);
- ret = pa_cvolume_get_fade(&cvolume, &volume->channel_map);
-
- return ret;
-}
-
-void pa_ext_volume_api_bvolume_set_rear_front_balance(pa_ext_volume_api_bvolume *volume, double balance) {
- pa_cvolume cvolume;
- pa_volume_t old_volume;
-
- pa_assert(volume);
-
- if (!pa_channel_map_can_fade(&volume->channel_map))
- return;
-
- pa_cvolume_reset(&cvolume, volume->channel_map.channels);
- pa_cvolume_set_fade(&cvolume, &volume->channel_map, balance);
- old_volume = volume->volume;
- pa_ext_volume_api_bvolume_from_cvolume(volume, &cvolume, &volume->channel_map);
- volume->volume = old_volume;
-}
-
-int pa_ext_volume_api_bvolume_balance_to_string(const pa_ext_volume_api_bvolume *volume, char **_r) {
- pa_strbuf *buf;
- unsigned i;
-
- pa_assert(volume);
- pa_assert(_r);
-
- if (!pa_ext_volume_api_bvolume_valid(volume, false, true))
- return -PA_ERR_INVALID;
-
- buf = pa_strbuf_new();
-
- for (i = 0; i < volume->channel_map.channels; i++) {
- if (i != 0)
- pa_strbuf_putc(buf, ' ');
-
- pa_strbuf_printf(buf, "%s:%.2f", pa_channel_position_to_string(volume->channel_map.map[i]), volume->balance[i]);
- }
-
- *_r = pa_strbuf_tostring_free(buf);
- return 0;
-}
-
-char *pa_ext_volume_api_bvolume_snprint_balance(char *buf, size_t buf_len,
- const pa_ext_volume_api_bvolume *volume) {
- char *e;
- unsigned channel;
- bool first = true;
-
- pa_assert(buf);
- pa_assert(buf_len > 0);
- pa_assert(volume);
-
- pa_init_i18n();
-
- if (!pa_ext_volume_api_bvolume_valid(volume, true, true)) {
- pa_snprintf(buf, buf_len, _("(invalid)"));
- return buf;
- }
-
- *(e = buf) = 0;
-
- for (channel = 0; channel < volume->channel_map.channels && buf_len > 1; channel++) {
- buf_len -= pa_snprintf(e, buf_len, "%s%s: %u%%",
- first ? "" : ", ",
- pa_channel_position_to_string(volume->channel_map.map[channel]),
- (unsigned) (volume->balance[channel] * 100 + 0.5));
-
- e = strchr(e, 0);
- first = false;
- }
-
- return buf;
-}
-
-static void extension_context_state_changed_cb(pa_extension *extension, unsigned phase) {
- struct userdata *u;
- pa_context_state_t context_state;
- pa_ext_volume_api_state_t api_state;
-
- pa_assert(extension);
- pa_assert(phase == 1 || phase == 2);
-
- u = get_userdata(extension->context, false);
- pa_assert(u);
-
- api_state = u->state;
-
- if (phase == 2) {
- if (u->state_notification_needed && u->state_callback)
- u->state_callback(u->context, u->state_callback_userdata);
-
- u->state_notification_needed = false;
- return;
- }
-
- context_state = pa_context_get_state(u->context);
-
- switch (context_state) {
- case PA_CONTEXT_UNCONNECTED:
- case PA_CONTEXT_CONNECTING:
- case PA_CONTEXT_AUTHORIZING:
- case PA_CONTEXT_SETTING_NAME:
- case PA_CONTEXT_READY:
- /* The volume api connection can only be initiated after the
- * context state becomes READY. */
- pa_assert(u->state == PA_EXT_VOLUME_API_STATE_UNCONNECTED);
- return;
-
- case PA_CONTEXT_FAILED:
- api_state = PA_EXT_VOLUME_API_STATE_FAILED;
- break;
-
- case PA_CONTEXT_TERMINATED:
- api_state = PA_EXT_VOLUME_API_STATE_TERMINATED;
- break;
- }
-
- if (api_state != u->state) {
- set_state(u, api_state, false);
- u->state_notification_needed = true;
- }
-}
-
-static void extension_kill_cb(pa_extension *extension) {
- pa_assert(extension);
-
- userdata_free(extension->userdata);
-}
-
-static void command_disconnect(struct userdata *u, pa_tagstruct *tagstruct) {
- pa_assert(u);
- pa_assert(tagstruct);
-
- if (!pa_tagstruct_eof(tagstruct)) {
- pa_log("Failed to parse the parameters of a DISCONNECT command.");
- pa_context_fail(u->context, PA_ERR_PROTOCOL);
- return;
- }
-
- if (u->state == PA_EXT_VOLUME_API_STATE_UNCONNECTED
- || u->state == PA_EXT_VOLUME_API_STATE_TERMINATED)
- return;
-
- /* We set the error to NOEXTENSION, because the assumption is that we only
- * receive a DISCONNECT command when the extension module is unloaded. */
- pa_context_set_error(u->context, PA_ERR_NOEXTENSION);
- set_state(u, PA_EXT_VOLUME_API_STATE_FAILED, true);
-}
-
-static void command_subscribe_event(struct userdata *u, pa_tagstruct *tagstruct) {
- pa_ext_volume_api_subscription_event_type_t event_type;
- pa_ext_volume_api_subscription_event_type_t facility;
- uint32_t idx;
-
- pa_assert(u);
- pa_assert(tagstruct);
-
- if (pa_tagstruct_getu32(tagstruct, &event_type) < 0
- || pa_tagstruct_getu32(tagstruct, &idx) < 0
- || !pa_tagstruct_eof(tagstruct)) {
- pa_log("Failed to parse the parameters of a SUBSCRIBE_EVENT command.");
- pa_context_fail(u->context, PA_ERR_PROTOCOL);
- return;
- }
-
- facility = event_type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
-
- if (u->subscription_mask & (1 << facility)) {
- if (u->subscribe_callback)
- u->subscribe_callback(u->context, event_type, idx, u->subscribe_callback_userdata);
- }
-}
-
-static void extension_process_command_cb(pa_extension *extension, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct) {
- struct userdata *u;
-
- pa_assert(extension);
- pa_assert(tagstruct);
-
- u = extension->userdata;
-
- if (u->state != PA_EXT_VOLUME_API_STATE_READY) {
- pa_pstream_send_error(extension->context->pstream, tag, PA_ERR_BADSTATE);
- return;
- }
-
- switch (command) {
- case PA_VOLUME_API_COMMAND_DISCONNECT:
- command_disconnect(u, tagstruct);
- break;
-
- case PA_VOLUME_API_COMMAND_SUBSCRIBE_EVENT:
- command_subscribe_event(u, tagstruct);
- break;
-
- default:
- pa_log("Received unrecognized command for the volume API extension: %u", command);
- pa_context_fail(u->context, PA_ERR_PROTOCOL);
- break;
- }
-}
-
-static struct userdata *userdata_new(pa_context *context) {
- struct userdata *u = NULL;
-
- pa_assert(context);
-
- u = pa_xnew0(struct userdata, 1);
- u->extension = pa_extension_new(context, PA_VOLUME_API_EXTENSION_NAME);
- u->extension->context_state_changed = extension_context_state_changed_cb;
- u->extension->kill = extension_kill_cb;
- u->extension->process_command = extension_process_command_cb;
- u->extension->userdata = u;
- u->context = context;
- u->state = PA_EXT_VOLUME_API_STATE_UNCONNECTED;
-
- pa_extension_put(u->extension);
-
- return u;
-}
-
-static void userdata_free(struct userdata *u) {
- pa_assert(u);
-
- if (u->extension)
- pa_extension_free(u->extension);
-
- pa_xfree(u);
-}
-
-static struct userdata *get_userdata(pa_context *context, bool create) {
- pa_extension *extension;
-
- pa_assert(context);
-
- extension = pa_context_get_extension(context, PA_VOLUME_API_EXTENSION_NAME);
-
- if (extension) {
- pa_assert(extension->userdata);
- return extension->userdata;
- }
-
- if (!create)
- return NULL;
-
- return userdata_new(context);
-}
-
-static void set_state(struct userdata *u, pa_ext_volume_api_state_t state, bool notify) {
- pa_assert(u);
-
- if (state == u->state)
- return;
-
- u->state = state;
-
- if (notify && u->state_callback)
- u->state_callback(u->context, u->state_callback_userdata);
-}
-
-static void connect_cb(pa_pdispatch *pdispatch, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct, void *userdata) {
- struct userdata *u = userdata;
- uint32_t version;
-
- pa_assert(u);
-
- if (command != PA_COMMAND_REPLY) {
- pa_context_handle_error(u->context, command, tagstruct, false);
- set_state(u, PA_EXT_VOLUME_API_STATE_FAILED, true);
- return;
- }
-
- pa_assert(tagstruct);
- pa_assert(u->state == PA_EXT_VOLUME_API_STATE_CONNECTING);
-
- if (pa_tagstruct_getu32(tagstruct, &version) < 0
- || version < 1)
- goto fail_parse;
-
- set_state(u, PA_EXT_VOLUME_API_STATE_READY, true);
-
- return;
-
-fail_parse:
- pa_log("Failed to parse the reply parameters of a CONNECT command.");
- pa_context_fail(u->context, PA_ERR_PROTOCOL);
-}
-
-int pa_ext_volume_api_connect(pa_context *context) {
- struct userdata *u;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
-
- PA_CHECK_VALIDITY_RETURN_ANY(context, context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, -1);
- PA_CHECK_VALIDITY_RETURN_ANY(context, context->version >= 14, PA_ERR_NOTSUPPORTED, -1);
-
- u = get_userdata(context, true);
-
- PA_CHECK_VALIDITY_RETURN_ANY(context, u->state == PA_EXT_VOLUME_API_STATE_UNCONNECTED
- || u->state == PA_EXT_VOLUME_API_STATE_TERMINATED, PA_ERR_BADSTATE, -1);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_CONNECT);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_VERSION);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, connect_cb, u, NULL);
-
- set_state(u, PA_EXT_VOLUME_API_STATE_CONNECTING, true);
-
- return 0;
-}
-
-void pa_ext_volume_api_disconnect(pa_context *context) {
- struct userdata *u;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
-
- u = get_userdata(context, false);
- if (!u)
- return;
-
- if (u->state == PA_EXT_VOLUME_API_STATE_UNCONNECTED
- || u->state == PA_EXT_VOLUME_API_STATE_FAILED
- || u->state == PA_EXT_VOLUME_API_STATE_TERMINATED)
- return;
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_DISCONNECT);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
-
- set_state(u, PA_EXT_VOLUME_API_STATE_TERMINATED, true);
-}
-
-void pa_ext_volume_api_set_state_callback(pa_context *context, pa_ext_volume_api_state_cb_t cb, void *userdata) {
- struct userdata *u;
-
- pa_assert(context);
-
- u = get_userdata(context, true);
- u->state_callback = cb;
- u->state_callback_userdata = userdata;
-}
-
-pa_ext_volume_api_state_t pa_ext_volume_api_get_state(pa_context *context) {
- struct userdata *u;
-
- pa_assert(context);
-
- u = get_userdata(context, false);
- if (!u)
- return PA_EXT_VOLUME_API_STATE_UNCONNECTED;
-
- return u->state;
-}
-
-pa_operation *pa_ext_volume_api_subscribe(pa_context *context, pa_ext_volume_api_subscription_mask_t mask,
- pa_context_success_cb_t cb, void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_SUBSCRIBE);
- pa_tagstruct_putu32(tagstruct, mask);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- u->subscription_mask = mask;
-
- return operation;
-}
-
-void pa_ext_volume_api_set_subscribe_callback(pa_context *context, pa_ext_volume_api_subscribe_cb_t cb,
- void *userdata) {
- struct userdata *u;
-
- pa_assert(context);
-
- u = get_userdata(context, true);
- u->subscribe_callback = cb;
- u->subscribe_callback_userdata = userdata;
-}
-
-static void get_server_info_cb(pa_pdispatch *pdispatch, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct,
- void *userdata) {
- pa_operation *operation = userdata;
- pa_ext_volume_api_server_info info, *p = &info;
-
- pa_assert(pdispatch);
- pa_assert(operation);
-
- if (!operation->context)
- goto finish;
-
- if (command != PA_COMMAND_REPLY) {
- if (pa_context_handle_error(operation->context, command, tagstruct, false) < 0)
- goto finish;
-
- p = NULL;
- } else {
- pa_assert(tagstruct);
-
- if (pa_tagstruct_getu32(tagstruct, &info.main_output_volume_control) < 0
- || pa_tagstruct_getu32(tagstruct, &info.main_input_volume_control) < 0
- || pa_tagstruct_getu32(tagstruct, &info.main_output_mute_control) < 0
- || pa_tagstruct_getu32(tagstruct, &info.main_input_mute_control) < 0
- || !pa_tagstruct_eof(tagstruct))
- goto fail_parse;
- }
-
- if (operation->callback) {
- pa_ext_volume_api_server_info_cb_t cb = (pa_ext_volume_api_server_info_cb_t) operation->callback;
- cb(operation->context, p, operation->userdata);
- }
-
-finish:
- pa_operation_done(operation);
- pa_operation_unref(operation);
- return;
-
-fail_parse:
- pa_log("Failed to parse the reply parameters of a GET_SERVER_INFO command.");
- pa_context_fail(operation->context, PA_ERR_PROTOCOL);
- goto finish;
-}
-
-pa_operation *pa_ext_volume_api_get_server_info(pa_context *context, pa_ext_volume_api_server_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_SERVER_INFO);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_server_info_cb, pa_operation_ref(operation),
- (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-static void volume_control_info_free(pa_ext_volume_api_volume_control_info *info) {
- pa_assert(info);
-
- if (info->proplist)
- pa_proplist_free(info->proplist);
-
- /* Description and name don't need to be freed, because they should point
- * to memory owned by pa_tagstruct, so they'll be freed when the tagstruct
- * is freed. */
-}
-
-static void get_volume_control_info_cb(pa_pdispatch *pdispatch, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct,
- void *userdata) {
- pa_operation *operation = userdata;
- int eol = 1;
- pa_ext_volume_api_volume_control_info info;
-
- pa_assert(pdispatch);
- pa_assert(operation);
-
- if (!operation->context)
- goto finish;
-
- if (command != PA_COMMAND_REPLY) {
- if (pa_context_handle_error(operation->context, command, tagstruct, false) < 0)
- goto finish;
-
- eol = -1;
- } else {
- pa_assert(tagstruct);
-
- while (!pa_tagstruct_eof(tagstruct)) {
- unsigned channel;
- bool convertible_to_dB;
-
- pa_zero(info);
- info.proplist = pa_proplist_new();
-
- if (pa_tagstruct_getu32(tagstruct, &info.index) < 0
- || info.index == PA_INVALID_INDEX
- || pa_tagstruct_gets(tagstruct, &info.name) < 0
- || !info.name || !*info.name
- || pa_tagstruct_gets(tagstruct, &info.description) < 0
- || !info.description
- || pa_tagstruct_get_proplist(tagstruct, info.proplist) < 0
- || pa_tagstruct_get_volume(tagstruct, &info.volume.volume) < 0
- || !PA_VOLUME_IS_VALID(info.volume.volume)
- || pa_tagstruct_get_channel_map(tagstruct, &info.volume.channel_map) < 0
- || !pa_channel_map_valid(&info.volume.channel_map))
- goto fail_parse;
-
- for (channel = 0; channel < info.volume.channel_map.channels; channel++) {
- uint64_t balance;
-
- if (pa_tagstruct_getu64(tagstruct, &balance) < 0)
- goto fail_parse;
-
- memcpy(&info.volume.balance[channel], &balance, sizeof(double));
-
- if (!pa_ext_volume_api_balance_valid(info.volume.balance[channel]))
- goto fail_parse;
- }
-
- if (pa_tagstruct_get_boolean(tagstruct, &convertible_to_dB) < 0)
- goto fail_parse;
-
- info.convertible_to_dB = convertible_to_dB;
-
- if (operation->callback) {
- pa_ext_volume_api_volume_control_info_cb_t cb =
- (pa_ext_volume_api_volume_control_info_cb_t) operation->callback;
- cb(operation->context, &info, 0, operation->userdata);
- }
-
- volume_control_info_free(&info);
- }
- }
-
- if (operation->callback) {
- pa_ext_volume_api_volume_control_info_cb_t cb =
- (pa_ext_volume_api_volume_control_info_cb_t) operation->callback;
- cb(operation->context, NULL, eol, operation->userdata);
- }
-
-finish:
- pa_operation_done(operation);
- pa_operation_unref(operation);
- return;
-
-fail_parse:
- pa_log("Failed to parse the reply parameters of a GET_VOLUME_CONTROL_INFO(_LIST) command.");
- pa_context_fail(operation->context, PA_ERR_PROTOCOL);
- volume_control_info_free(&info);
- goto finish;
-}
-
-pa_operation *pa_ext_volume_api_get_volume_control_info_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_volume_control_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_VOLUME_CONTROL_INFO);
- pa_tagstruct_putu32(tagstruct, idx);
- pa_tagstruct_puts(tagstruct, NULL);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_volume_control_info_cb,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_get_volume_control_info_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_volume_control_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, name && *name, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_VOLUME_CONTROL_INFO);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, name);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_volume_control_info_cb,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_get_volume_control_info_list(pa_context *context,
- pa_ext_volume_api_volume_control_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_VOLUME_CONTROL_INFO_LIST);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_volume_control_info_cb,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_set_volume_control_volume_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_bvolume *volume,
- int set_volume, int set_balance,
- pa_context_success_cb_t cb, void *userdata) {
- struct userdata *u;
- pa_volume_t v;
- pa_channel_map channel_map;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
- unsigned i;
-
- pa_assert(context);
- pa_assert(volume);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
- PA_CHECK_VALIDITY_RETURN_NULL(context, set_volume || set_balance, PA_ERR_INVALID);
- PA_CHECK_VALIDITY_RETURN_NULL(context, pa_ext_volume_api_bvolume_valid(volume, set_volume, set_balance),
- PA_ERR_INVALID);
-
- v = volume->volume;
-
- if (!set_volume)
- v = PA_VOLUME_INVALID;
-
- channel_map = volume->channel_map;
-
- if (!set_balance)
- pa_channel_map_init(&channel_map);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_SET_VOLUME_CONTROL_VOLUME);
- pa_tagstruct_putu32(tagstruct, idx);
- pa_tagstruct_puts(tagstruct, NULL);
- pa_tagstruct_put_volume(tagstruct, v);
- pa_tagstruct_put_channel_map(tagstruct, &channel_map);
-
- for (i = 0; i < channel_map.channels; i++) {
- uint64_t balance;
-
- memcpy(&balance, &volume->balance[i], sizeof(uint64_t));
- pa_tagstruct_putu64(tagstruct, balance);
- }
-
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_set_volume_control_volume_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_bvolume *volume,
- int set_volume, int set_balance,
- pa_context_success_cb_t cb, void *userdata) {
- struct userdata *u;
- pa_volume_t v;
- pa_channel_map channel_map;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
- unsigned i;
-
- pa_assert(context);
- pa_assert(volume);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, name && *name, PA_ERR_INVALID);
- PA_CHECK_VALIDITY_RETURN_NULL(context, set_volume || set_balance, PA_ERR_INVALID);
- PA_CHECK_VALIDITY_RETURN_NULL(context, pa_ext_volume_api_bvolume_valid(volume, set_volume, set_balance),
- PA_ERR_INVALID);
-
- v = volume->volume;
-
- if (!set_volume)
- v = PA_VOLUME_INVALID;
-
- channel_map = volume->channel_map;
-
- if (!set_balance)
- pa_channel_map_init(&channel_map);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_SET_VOLUME_CONTROL_VOLUME);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, name);
- pa_tagstruct_put_volume(tagstruct, v);
- pa_tagstruct_put_channel_map(tagstruct, &channel_map);
-
- for (i = 0; i < channel_map.channels; i++) {
- uint64_t balance;
-
- memcpy(&balance, &volume->balance[i], sizeof(uint64_t));
- pa_tagstruct_putu64(tagstruct, balance);
- }
-
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-static void mute_control_info_free(pa_ext_volume_api_mute_control_info *info) {
- pa_assert(info);
-
- if (info->proplist)
- pa_proplist_free(info->proplist);
-
- /* Description and name don't need to be freed, because they should point
- * to memory owned by pa_tagstruct, so they'll be freed when the tagstruct
- * is freed. */
-}
-
-static void get_mute_control_info_cb(pa_pdispatch *pdispatch, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct,
- void *userdata) {
- pa_operation *operation = userdata;
- int eol = 1;
- pa_ext_volume_api_mute_control_info info;
-
- pa_assert(pdispatch);
- pa_assert(operation);
-
- if (!operation->context)
- goto finish;
-
- if (command != PA_COMMAND_REPLY) {
- if (pa_context_handle_error(operation->context, command, tagstruct, false) < 0)
- goto finish;
-
- eol = -1;
- } else {
- pa_assert(tagstruct);
-
- while (!pa_tagstruct_eof(tagstruct)) {
- bool mute;
-
- pa_zero(info);
- info.proplist = pa_proplist_new();
-
- if (pa_tagstruct_getu32(tagstruct, &info.index) < 0
- || info.index == PA_INVALID_INDEX
- || pa_tagstruct_gets(tagstruct, &info.name) < 0
- || !info.name || !*info.name
- || pa_tagstruct_gets(tagstruct, &info.description) < 0
- || !info.description
- || pa_tagstruct_get_proplist(tagstruct, info.proplist) < 0
- || pa_tagstruct_get_boolean(tagstruct, &mute) < 0)
- goto fail_parse;
-
- info.mute = mute;
-
- if (operation->callback) {
- pa_ext_volume_api_mute_control_info_cb_t cb =
- (pa_ext_volume_api_mute_control_info_cb_t) operation->callback;
- cb(operation->context, &info, 0, operation->userdata);
- }
-
- mute_control_info_free(&info);
- }
- }
-
- if (operation->callback) {
- pa_ext_volume_api_mute_control_info_cb_t cb =
- (pa_ext_volume_api_mute_control_info_cb_t) operation->callback;
- cb(operation->context, NULL, eol, operation->userdata);
- }
-
-finish:
- pa_operation_done(operation);
- pa_operation_unref(operation);
- return;
-
-fail_parse:
- pa_log("Failed to parse the reply parameters of a GET_MUTE_CONTROL_INFO(_LIST) command.");
- pa_context_fail(operation->context, PA_ERR_PROTOCOL);
- mute_control_info_free(&info);
- goto finish;
-}
-
-pa_operation *pa_ext_volume_api_get_mute_control_info_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_mute_control_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_MUTE_CONTROL_INFO);
- pa_tagstruct_putu32(tagstruct, idx);
- pa_tagstruct_puts(tagstruct, NULL);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_mute_control_info_cb,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_get_mute_control_info_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_mute_control_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, name && *name, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_MUTE_CONTROL_INFO);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, name);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_mute_control_info_cb,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_get_mute_control_info_list(pa_context *context,
- pa_ext_volume_api_mute_control_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_MUTE_CONTROL_INFO_LIST);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_mute_control_info_cb,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_set_mute_control_mute_by_index(pa_context *context, uint32_t idx, int mute,
- pa_context_success_cb_t cb, void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_SET_MUTE_CONTROL_MUTE);
- pa_tagstruct_putu32(tagstruct, idx);
- pa_tagstruct_puts(tagstruct, NULL);
- pa_tagstruct_put_boolean(tagstruct, mute);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_set_mute_control_mute_by_name(pa_context *context, const char *name, int mute,
- pa_context_success_cb_t cb, void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, name && *name, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_SET_MUTE_CONTROL_MUTE);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, name);
- pa_tagstruct_put_boolean(tagstruct, mute);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-static void device_info_free(pa_ext_volume_api_device_info *info) {
- pa_assert(info);
-
- if (info->proplist)
- pa_proplist_free(info->proplist);
-
- /* The strings in device_types point to memory owned by pa_tagstruct, so we
- * only need to free the device_types array. */
- pa_xfree(info->device_types);
-
- /* Description and name don't need to be freed, because they should point
- * to memory owned by pa_tagstruct, so they'll be freed when the tagstruct
- * is freed. */
-}
-
-static void get_device_info_cb(pa_pdispatch *pdispatch, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct,
- void *userdata) {
- pa_operation *operation = userdata;
- int eol = 1;
- pa_ext_volume_api_device_info info;
-
- pa_assert(pdispatch);
- pa_assert(operation);
-
- if (!operation->context)
- goto finish;
-
- if (command != PA_COMMAND_REPLY) {
- if (pa_context_handle_error(operation->context, command, tagstruct, false) < 0)
- goto finish;
-
- eol = -1;
- } else {
- pa_assert(tagstruct);
-
- while (!pa_tagstruct_eof(tagstruct)) {
- uint8_t direction;
- unsigned i;
-
- pa_zero(info);
- info.proplist = pa_proplist_new();
-
- if (pa_tagstruct_getu32(tagstruct, &info.index) < 0
- || info.index == PA_INVALID_INDEX
- || pa_tagstruct_gets(tagstruct, &info.name) < 0
- || !info.name || !*info.name
- || pa_tagstruct_gets(tagstruct, &info.description) < 0
- || !info.description
- || pa_tagstruct_getu8(tagstruct, &direction) < 0
- || !pa_direction_valid(direction)
- || pa_tagstruct_getu32(tagstruct, &info.n_device_types) < 0
- || info.n_device_types > 1000)
- goto fail_parse;
-
- info.direction = direction;
-
- if (info.n_device_types > 0)
- info.device_types = pa_xnew0(const char *, info.n_device_types);
-
- for (i = 0; i < info.n_device_types; i++) {
- if (pa_tagstruct_gets(tagstruct, &info.device_types[i]) < 0
- || !info.device_types[i] || !*info.device_types[i])
- goto fail_parse;
- }
-
- if (pa_tagstruct_get_proplist(tagstruct, info.proplist) < 0
- || pa_tagstruct_getu32(tagstruct, &info.volume_control) < 0
- || pa_tagstruct_getu32(tagstruct, &info.mute_control) < 0)
- goto fail_parse;
-
- if (operation->callback) {
- pa_ext_volume_api_device_info_cb_t cb = (pa_ext_volume_api_device_info_cb_t) operation->callback;
- cb(operation->context, &info, 0, operation->userdata);
- }
-
- device_info_free(&info);
- }
- }
-
- if (operation->callback) {
- pa_ext_volume_api_device_info_cb_t cb = (pa_ext_volume_api_device_info_cb_t) operation->callback;
- cb(operation->context, NULL, eol, operation->userdata);
- }
-
-finish:
- pa_operation_done(operation);
- pa_operation_unref(operation);
- return;
-
-fail_parse:
- pa_log("Failed to parse the reply parameters of a GET_DEVICE_INFO(_LIST) command.");
- pa_context_fail(operation->context, PA_ERR_PROTOCOL);
- device_info_free(&info);
- goto finish;
-}
-
-pa_operation *pa_ext_volume_api_get_device_info_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_device_info_cb_t cb, void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_DEVICE_INFO);
- pa_tagstruct_putu32(tagstruct, idx);
- pa_tagstruct_puts(tagstruct, NULL);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_device_info_cb, pa_operation_ref(operation),
- (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_get_device_info_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_device_info_cb_t cb, void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, name && *name, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_DEVICE_INFO);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, name);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_device_info_cb, pa_operation_ref(operation),
- (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_get_device_info_list(pa_context *context, pa_ext_volume_api_device_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_DEVICE_INFO_LIST);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_device_info_cb, pa_operation_ref(operation),
- (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-static void stream_info_free(pa_ext_volume_api_stream_info *info) {
- pa_assert(info);
-
- if (info->proplist)
- pa_proplist_free(info->proplist);
-
- /* Description and name don't need to be freed, because they should point
- * to memory owned by pa_tagstruct, so they'll be freed when the tagstruct
- * is freed. */
-}
-
-static void get_stream_info_cb(pa_pdispatch *pdispatch, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct,
- void *userdata) {
- pa_operation *operation = userdata;
- int eol = 1;
- pa_ext_volume_api_stream_info info;
-
- pa_assert(pdispatch);
- pa_assert(operation);
-
- if (!operation->context)
- goto finish;
-
- if (command != PA_COMMAND_REPLY) {
- if (pa_context_handle_error(operation->context, command, tagstruct, false) < 0)
- goto finish;
-
- eol = -1;
- } else {
- pa_assert(tagstruct);
-
- while (!pa_tagstruct_eof(tagstruct)) {
- uint8_t direction;
-
- pa_zero(info);
- info.proplist = pa_proplist_new();
-
- if (pa_tagstruct_getu32(tagstruct, &info.index) < 0
- || info.index == PA_INVALID_INDEX
- || pa_tagstruct_gets(tagstruct, &info.name) < 0
- || !info.name || !*info.name
- || pa_tagstruct_gets(tagstruct, &info.description) < 0
- || !info.description
- || pa_tagstruct_getu8(tagstruct, &direction) < 0
- || !pa_direction_valid(direction)
- || pa_tagstruct_get_proplist(tagstruct, info.proplist) < 0
- || pa_tagstruct_getu32(tagstruct, &info.volume_control) < 0
- || pa_tagstruct_getu32(tagstruct, &info.mute_control) < 0)
- goto fail_parse;
-
- info.direction = direction;
-
- if (operation->callback) {
- pa_ext_volume_api_stream_info_cb_t cb = (pa_ext_volume_api_stream_info_cb_t) operation->callback;
- cb(operation->context, &info, 0, operation->userdata);
- }
-
- stream_info_free(&info);
- }
- }
-
- if (operation->callback) {
- pa_ext_volume_api_stream_info_cb_t cb = (pa_ext_volume_api_stream_info_cb_t) operation->callback;
- cb(operation->context, NULL, eol, operation->userdata);
- }
-
-finish:
- pa_operation_done(operation);
- pa_operation_unref(operation);
- return;
-
-fail_parse:
- pa_log("Failed to parse the reply parameters of a GET_STREAM_INFO(_LIST) command.");
- pa_context_fail(operation->context, PA_ERR_PROTOCOL);
- stream_info_free(&info);
- goto finish;
-}
-
-pa_operation *pa_ext_volume_api_get_stream_info_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_stream_info_cb_t cb, void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_STREAM_INFO);
- pa_tagstruct_putu32(tagstruct, idx);
- pa_tagstruct_puts(tagstruct, NULL);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_stream_info_cb, pa_operation_ref(operation),
- (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_get_stream_info_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_stream_info_cb_t cb, void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, name && *name, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_STREAM_INFO);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, name);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_stream_info_cb, pa_operation_ref(operation),
- (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_get_stream_info_list(pa_context *context, pa_ext_volume_api_stream_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_STREAM_INFO_LIST);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_stream_info_cb, pa_operation_ref(operation),
- (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-static void audio_group_info_free(pa_ext_volume_api_audio_group_info *info) {
- pa_assert(info);
-
- if (info->proplist)
- pa_proplist_free(info->proplist);
-
- /* Description and name don't need to be freed, because they should point
- * to memory owned by pa_tagstruct, so they'll be freed when the tagstruct
- * is freed. */
-}
-
-static void get_audio_group_info_cb(pa_pdispatch *pdispatch, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct,
- void *userdata) {
- pa_operation *operation = userdata;
- int eol = 1;
- pa_ext_volume_api_audio_group_info info;
-
- pa_assert(pdispatch);
- pa_assert(operation);
-
- if (!operation->context)
- goto finish;
-
- if (command != PA_COMMAND_REPLY) {
- if (pa_context_handle_error(operation->context, command, tagstruct, false) < 0)
- goto finish;
-
- eol = -1;
- } else {
- pa_assert(tagstruct);
-
- while (!pa_tagstruct_eof(tagstruct)) {
- pa_zero(info);
- info.proplist = pa_proplist_new();
-
- if (pa_tagstruct_getu32(tagstruct, &info.index) < 0
- || info.index == PA_INVALID_INDEX
- || pa_tagstruct_gets(tagstruct, &info.name) < 0
- || !info.name || !*info.name
- || pa_tagstruct_gets(tagstruct, &info.description) < 0
- || !info.description
- || pa_tagstruct_get_proplist(tagstruct, info.proplist) < 0
- || pa_tagstruct_getu32(tagstruct, &info.volume_control) < 0
- || pa_tagstruct_getu32(tagstruct, &info.mute_control) < 0)
- goto fail_parse;
-
- if (operation->callback) {
- pa_ext_volume_api_audio_group_info_cb_t cb =
- (pa_ext_volume_api_audio_group_info_cb_t) operation->callback;
- cb(operation->context, &info, 0, operation->userdata);
- }
-
- audio_group_info_free(&info);
- }
- }
-
- if (operation->callback) {
- pa_ext_volume_api_audio_group_info_cb_t cb = (pa_ext_volume_api_audio_group_info_cb_t) operation->callback;
- cb(operation->context, NULL, eol, operation->userdata);
- }
-
-finish:
- pa_operation_done(operation);
- pa_operation_unref(operation);
- return;
-
-fail_parse:
- pa_log("Failed to parse the reply parameters of a GET_AUDIO_GROUP_INFO(_LIST) command.");
- pa_context_fail(operation->context, PA_ERR_PROTOCOL);
- audio_group_info_free(&info);
- goto finish;
-}
-
-pa_operation *pa_ext_volume_api_get_audio_group_info_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_audio_group_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_AUDIO_GROUP_INFO);
- pa_tagstruct_putu32(tagstruct, idx);
- pa_tagstruct_puts(tagstruct, NULL);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_audio_group_info_cb,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_get_audio_group_info_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_audio_group_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(context, name && *name, PA_ERR_INVALID);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_AUDIO_GROUP_INFO);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, name);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_audio_group_info_cb,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
-
-pa_operation *pa_ext_volume_api_get_audio_group_info_list(pa_context *context,
- pa_ext_volume_api_audio_group_info_cb_t cb,
- void *userdata) {
- struct userdata *u;
- pa_operation *operation;
- pa_tagstruct *tagstruct;
- uint32_t tag;
-
- pa_assert(context);
- pa_assert(cb);
-
- u = get_userdata(context, false);
- PA_CHECK_VALIDITY_RETURN_NULL(context, u && u->state == PA_EXT_VOLUME_API_STATE_READY, PA_ERR_BADSTATE);
-
- operation = pa_operation_new(context, NULL, (pa_operation_cb_t) cb, userdata);
-
- tagstruct = pa_tagstruct_command(context, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(tagstruct, PA_INVALID_INDEX);
- pa_tagstruct_puts(tagstruct, PA_VOLUME_API_EXTENSION_NAME);
- pa_tagstruct_putu32(tagstruct, PA_VOLUME_API_COMMAND_GET_AUDIO_GROUP_INFO_LIST);
- pa_pstream_send_tagstruct(context->pstream, tagstruct);
- pa_pdispatch_register_reply(context->pdispatch, tag, DEFAULT_TIMEOUT, get_audio_group_info_cb,
- pa_operation_ref(operation), (pa_free_cb_t) pa_operation_unref);
-
- return operation;
-}
+++ /dev/null
-#ifndef fooextvolumeapihfoo
-#define fooextvolumeapihfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2014 Intel Corporation
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <pulse/cdecl.h>
-#include <pulse/context.h>
-#include <pulse/volume.h>
-
-/* This API is temporary, and has no stability guarantees whatsoever. Think
- * twice before making anything that relies on this API. This is undocumented
- * for a reason. */
-
-PA_C_DECL_BEGIN
-
-typedef struct pa_ext_volume_api_bvolume pa_ext_volume_api_bvolume;
-typedef struct pa_ext_volume_api_server_info pa_ext_volume_api_server_info;
-typedef struct pa_ext_volume_api_volume_control_info pa_ext_volume_api_volume_control_info;
-typedef struct pa_ext_volume_api_mute_control_info pa_ext_volume_api_mute_control_info;
-typedef struct pa_ext_volume_api_device_info pa_ext_volume_api_device_info;
-typedef struct pa_ext_volume_api_stream_info pa_ext_volume_api_stream_info;
-typedef struct pa_ext_volume_api_audio_group_info pa_ext_volume_api_audio_group_info;
-
-struct pa_ext_volume_api_bvolume {
- pa_volume_t volume;
- double balance[PA_CHANNELS_MAX];
- pa_channel_map channel_map;
-};
-
-int pa_ext_volume_api_balance_valid(double balance) PA_GCC_CONST;
-int pa_ext_volume_api_bvolume_valid(const pa_ext_volume_api_bvolume *volume, int check_volume, int check_balance)
- PA_GCC_PURE;
-void pa_ext_volume_api_bvolume_init_invalid(pa_ext_volume_api_bvolume *volume);
-void pa_ext_volume_api_bvolume_init(pa_ext_volume_api_bvolume *bvolume, pa_volume_t volume, pa_channel_map *map);
-void pa_ext_volume_api_bvolume_init_mono(pa_ext_volume_api_bvolume *bvolume, pa_volume_t volume);
-int pa_ext_volume_api_bvolume_parse_balance(const char *str, pa_ext_volume_api_bvolume *bvolume);
-int pa_ext_volume_api_bvolume_equal(const pa_ext_volume_api_bvolume *a, const pa_ext_volume_api_bvolume *b,
- int check_volume, int check_balance) PA_GCC_PURE;
-void pa_ext_volume_api_bvolume_from_cvolume(pa_ext_volume_api_bvolume *bvolume, const pa_cvolume *cvolume,
- const pa_channel_map *map);
-void pa_ext_volume_api_bvolume_to_cvolume(const pa_ext_volume_api_bvolume *bvolume, pa_cvolume *cvolume);
-void pa_ext_volume_api_bvolume_copy_balance(pa_ext_volume_api_bvolume *to,
- const pa_ext_volume_api_bvolume *from);
-void pa_ext_volume_api_bvolume_reset_balance(pa_ext_volume_api_bvolume *volume, const pa_channel_map *map);
-void pa_ext_volume_api_bvolume_remap(pa_ext_volume_api_bvolume *volume, const pa_channel_map *to);
-double pa_ext_volume_api_bvolume_get_left_right_balance(const pa_ext_volume_api_bvolume *volume) PA_GCC_PURE;
-void pa_ext_volume_api_bvolume_set_left_right_balance(pa_ext_volume_api_bvolume *volume, double balance);
-double pa_ext_volume_api_bvolume_get_rear_front_balance(const pa_ext_volume_api_bvolume *volume) PA_GCC_PURE;
-void pa_ext_volume_api_bvolume_set_rear_front_balance(pa_ext_volume_api_bvolume *volume, double balance);
-int pa_ext_volume_api_bvolume_balance_to_string(const pa_ext_volume_api_bvolume *volume, char **_r);
-
-#define PA_EXT_VOLUME_API_BVOLUME_SNPRINT_BALANCE_MAX 500
-char *pa_ext_volume_api_bvolume_snprint_balance(char *buf, size_t buf_size,
- const pa_ext_volume_api_bvolume *volume);
-
-typedef enum pa_ext_volume_api_state {
- PA_EXT_VOLUME_API_STATE_UNCONNECTED,
- PA_EXT_VOLUME_API_STATE_CONNECTING,
- PA_EXT_VOLUME_API_STATE_READY,
- PA_EXT_VOLUME_API_STATE_FAILED,
- PA_EXT_VOLUME_API_STATE_TERMINATED
-} pa_ext_volume_api_state_t;
-
-int pa_ext_volume_api_connect(pa_context *context);
-void pa_ext_volume_api_disconnect(pa_context *context);
-
-typedef void (*pa_ext_volume_api_state_cb_t)(pa_context *context, void *userdata);
-void pa_ext_volume_api_set_state_callback(pa_context *context, pa_ext_volume_api_state_cb_t cb, void *userdata);
-pa_ext_volume_api_state_t pa_ext_volume_api_get_state(pa_context *context);
-
-typedef enum pa_ext_volume_api_subscription_mask {
- PA_EXT_VOLUME_API_SUBSCRIPTION_MASK_NULL = 0x0U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_MASK_SERVER = 0x1U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_MASK_VOLUME_CONTROL = 0x2U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_MASK_MUTE_CONTROL = 0x4U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_MASK_DEVICE = 0x8U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_MASK_STREAM = 0x10U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_MASK_AUDIO_GROUP = 0x20U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_MASK_ALL = 0x3FU,
-} pa_ext_volume_api_subscription_mask_t;
-
-pa_operation *pa_ext_volume_api_subscribe(pa_context *context, pa_ext_volume_api_subscription_mask_t mask,
- pa_context_success_cb_t cb, void *userdata);
-
-typedef enum pa_ext_volume_api_subscription_event_type {
- PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_SERVER = 0x0U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_VOLUME_CONTROL = 0x1U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_MUTE_CONTROL = 0x2U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_DEVICE = 0x3U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_STREAM = 0x4U,
- PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_AUDIO_GROUP = 0x5U,
-} pa_ext_volume_api_subscription_event_type_t;
-
-typedef void (*pa_ext_volume_api_subscribe_cb_t)(pa_context *context,
- pa_ext_volume_api_subscription_event_type_t event_type,
- uint32_t idx, void *userdata);
-void pa_ext_volume_api_set_subscribe_callback(pa_context *context, pa_ext_volume_api_subscribe_cb_t cb,
- void *userdata);
-
-struct pa_ext_volume_api_server_info {
- uint32_t main_output_volume_control;
- uint32_t main_input_volume_control;
- uint32_t main_output_mute_control;
- uint32_t main_input_mute_control;
-};
-
-typedef void (*pa_ext_volume_api_server_info_cb_t)(pa_context *context, const pa_ext_volume_api_server_info *info,
- void *userdata);
-pa_operation *pa_ext_volume_api_get_server_info(pa_context *context, pa_ext_volume_api_server_info_cb_t cb,
- void *userdata);
-
-struct pa_ext_volume_api_volume_control_info {
- uint32_t index;
- const char *name;
- const char *description;
- pa_proplist *proplist;
- pa_ext_volume_api_bvolume volume;
- int convertible_to_dB;
-};
-
-typedef void (*pa_ext_volume_api_volume_control_info_cb_t)(pa_context *context,
- const pa_ext_volume_api_volume_control_info *info,
- int eol, void *userdata);
-pa_operation *pa_ext_volume_api_get_volume_control_info_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_volume_control_info_cb_t cb,
- void *userdata);
-pa_operation *pa_ext_volume_api_get_volume_control_info_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_volume_control_info_cb_t cb,
- void *userdata);
-pa_operation *pa_ext_volume_api_get_volume_control_info_list(pa_context *context,
- pa_ext_volume_api_volume_control_info_cb_t cb,
- void *userdata);
-
-pa_operation *pa_ext_volume_api_set_volume_control_volume_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_bvolume *volume,
- int set_volume, int set_balance,
- pa_context_success_cb_t cb, void *userdata);
-pa_operation *pa_ext_volume_api_set_volume_control_volume_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_bvolume *volume,
- int set_volume, int set_balance,
- pa_context_success_cb_t cb, void *userdata);
-
-struct pa_ext_volume_api_mute_control_info {
- uint32_t index;
- const char *name;
- const char *description;
- pa_proplist *proplist;
- int mute;
-};
-
-typedef void (*pa_ext_volume_api_mute_control_info_cb_t)(pa_context *context,
- const pa_ext_volume_api_mute_control_info *info, int eol,
- void *userdata);
-pa_operation *pa_ext_volume_api_get_mute_control_info_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_mute_control_info_cb_t cb,
- void *userdata);
-pa_operation *pa_ext_volume_api_get_mute_control_info_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_mute_control_info_cb_t cb,
- void *userdata);
-pa_operation *pa_ext_volume_api_get_mute_control_info_list(pa_context *context,
- pa_ext_volume_api_mute_control_info_cb_t cb,
- void *userdata);
-
-pa_operation *pa_ext_volume_api_set_mute_control_mute_by_index(pa_context *context, uint32_t idx, int mute,
- pa_context_success_cb_t cb, void *userdata);
-pa_operation *pa_ext_volume_api_set_mute_control_mute_by_name(pa_context *context, const char *name, int mute,
- pa_context_success_cb_t cb, void *userdata);
-
-struct pa_ext_volume_api_device_info {
- uint32_t index;
- const char *name;
- const char *description;
- pa_direction_t direction;
- const char **device_types;
- uint32_t n_device_types;
- pa_proplist *proplist;
- uint32_t volume_control;
- uint32_t mute_control;
-};
-
-typedef void (*pa_ext_volume_api_device_info_cb_t)(pa_context *context, const pa_ext_volume_api_device_info *info,
- int eol, void *userdata);
-pa_operation *pa_ext_volume_api_get_device_info_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_device_info_cb_t cb, void *userdata);
-pa_operation *pa_ext_volume_api_get_device_info_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_device_info_cb_t cb, void *userdata);
-pa_operation *pa_ext_volume_api_get_device_info_list(pa_context *context, pa_ext_volume_api_device_info_cb_t cb,
- void *userdata);
-
-struct pa_ext_volume_api_stream_info {
- uint32_t index;
- const char *name;
- const char *description;
- pa_direction_t direction;
- pa_proplist *proplist;
- uint32_t volume_control;
- uint32_t mute_control;
-};
-
-typedef void (*pa_ext_volume_api_stream_info_cb_t)(pa_context *context, const pa_ext_volume_api_stream_info *info,
- int eol, void *userdata);
-pa_operation *pa_ext_volume_api_get_stream_info_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_stream_info_cb_t cb, void *userdata);
-pa_operation *pa_ext_volume_api_get_stream_info_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_stream_info_cb_t cb, void *userdata);
-pa_operation *pa_ext_volume_api_get_stream_info_list(pa_context *context, pa_ext_volume_api_stream_info_cb_t cb,
- void *userdata);
-
-struct pa_ext_volume_api_audio_group_info {
- uint32_t index;
- const char *name;
- const char *description;
- pa_proplist *proplist;
- uint32_t volume_control;
- uint32_t mute_control;
-};
-
-typedef void (*pa_ext_volume_api_audio_group_info_cb_t)(pa_context *context,
- const pa_ext_volume_api_audio_group_info *info, int eol,
- void *userdata);
-pa_operation *pa_ext_volume_api_get_audio_group_info_by_index(pa_context *context, uint32_t idx,
- pa_ext_volume_api_audio_group_info_cb_t cb,
- void *userdata);
-pa_operation *pa_ext_volume_api_get_audio_group_info_by_name(pa_context *context, const char *name,
- pa_ext_volume_api_audio_group_info_cb_t cb,
- void *userdata);
-pa_operation *pa_ext_volume_api_get_audio_group_info_list(pa_context *context,
- pa_ext_volume_api_audio_group_info_cb_t cb,
- void *userdata);
-
-PA_C_DECL_END
-
-#endif