aboutsummaryrefslogtreecommitdiffstats
path: root/meta-agl-profile-core/recipes-multimedia/pulseaudio
diff options
context:
space:
mode:
authorGeorge Kiagiadakis <george.kiagiadakis@collabora.com>2018-07-20 14:32:51 +0300
committerJan-Simon Moeller <jsmoeller@linuxfoundation.org>2018-08-01 09:46:18 +0000
commit4464b68290669f133c17e7135dc86be9c4019326 (patch)
tree58a18df13e96826a82cda5778553bb2056d9940c /meta-agl-profile-core/recipes-multimedia/pulseaudio
parent0037291bf3011ae006c8ecd42764aebc4a32c826 (diff)
pulseaudio: remove unused .patch files from the repository
No recipe uses those. Change-Id: Iec368fcf6e6340866c6d346a438e21c8cb7960ef Signed-off-by: George Kiagiadakis <george.kiagiadakis@collabora.com>
Diffstat (limited to 'meta-agl-profile-core/recipes-multimedia/pulseaudio')
-rw-r--r--meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0008-install-files-for-a-module-development.patch53
-rw-r--r--meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0010-volume-ramp-additions-to-the-low-level-infra.patch503
-rw-r--r--meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0011-volume-ramp-adding-volume-ramping-to-sink-input.patch159
-rw-r--r--meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0012-volume-ramp-add-volume-ramping-to-sink.patch159
-rw-r--r--meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0013-add-internal-corking-state-for-sink-input.patch72
-rw-r--r--meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0020-core-util-Add-pa_join.patch37
-rw-r--r--meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0021-dynarray-Add-pa_dynarray_get_raw_array.patch21
-rw-r--r--meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0022-device-port-Add-pa_device_port.active.patch198
-rw-r--r--meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0030-volume-api-Add-libvolume-api.patch6118
-rw-r--r--meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0031-Add-module-main-volume-policy.patch1418
-rw-r--r--meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0039-main-volume-policy-adapt-to-pa6rev.patch11
11 files changed, 0 insertions, 8749 deletions
diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0008-install-files-for-a-module-development.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0008-install-files-for-a-module-development.patch
deleted file mode 100644
index ac164d643..000000000
--- a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0008-install-files-for-a-module-development.patch
+++ /dev/null
@@ -1,53 +0,0 @@
---- a/Makefile.am 2016-04-12 11:28:10.832997230 +0200
-+++ b/Makefile.am 2016-04-12 11:32:41.868996777 +0200
-@@ -49,7 +49,13 @@
- vala/libpulse-simple.deps vala/libpulse-simple.vapi
-
- pkgconfigdir = $(libdir)/pkgconfig
--pkgconfig_DATA = libpulse.pc libpulse-simple.pc
-+pkgconfig_DATA = libpulse.pc libpulse-simple.pc pulseaudio-module-devel.pc
-+
-+moduledev_DATA = pulsecore-config.h $(top_srcdir)/src/pulsecore/*.h
-+moduledevdir = $(includedir)/pulsemodule/pulsecore
-+
-+moduledevinternal_DATA = src/pulse/internal.h src/pulse/client-conf.h src/pulse/fork-detect.h
-+moduledevinternaldir = $(includedir)/pulsemodule/pulse
-
- if HAVE_GLIB20
- pkgconfig_DATA += \
-@@ -103,6 +109,9 @@
- check-daemon:
- $(MAKE) -C src check-daemon
-
-+pulsecore-config.h: config.h
-+ cp $< $@
-+
- .PHONY: homepage distcleancheck doxygen
-
- # see git-version-gen
---- a/configure.ac 2016-04-12 11:34:10.605996629 +0200
-+++ b/configure.ac 2016-04-12 11:37:43.502996274 +0200
-@@ -1464,6 +1464,7 @@
- man/default.pa.5.xml
- man/pulse-cli-syntax.5.xml
- man/start-pulseaudio-x11.1.xml
-+pulseaudio-module-devel.pc
- ])
-
- AC_CONFIG_FILES([src/esdcompat:src/daemon/esdcompat.in], [chmod +x src/esdcompat])
---- /dev/null 2016-03-15 16:08:23.302999643 +0100
-+++ b/pulseaudio-module-devel.pc.in 2016-03-17 16:16:58.427977484 +0100
-@@ -0,0 +1,12 @@
-+prefix=@prefix@
-+exec_prefix=@exec_prefix@
-+libdir=@libdir@
-+includedir=@includedir@
-+modlibexecdir=@modlibexecdir@
-+
-+Name: pulseaudio-module-devel
-+Description: PulseAudio Module Development Interface
-+Version: @PACKAGE_VERSION@
-+Libs: -L${libdir} -L${libdir}/pulseaudio -L${modlibexecdir} -lpulsecommon-@PA_MAJORMINOR@ -lpulsecore-@PA_MAJORMINOR@ -lprotocol-native
-+Libs.private:
-+Cflags: -I${includedir}/pulsemodule -D_REENTRANT
-
diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0010-volume-ramp-additions-to-the-low-level-infra.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0010-volume-ramp-additions-to-the-low-level-infra.patch
deleted file mode 100644
index e249bc438..000000000
--- a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0010-volume-ramp-additions-to-the-low-level-infra.patch
+++ /dev/null
@@ -1,503 +0,0 @@
---- a/src/map-file 2016-04-12 15:03:17.009975690 +0200
-+++ b/src/map-file 2016-04-12 15:03:52.389975631 +0200
-@@ -136,6 +136,9 @@
- pa_cvolume_merge;
- pa_cvolume_min;
- pa_cvolume_min_mask;
-+pa_cvolume_ramp_init;
-+pa_cvolume_ramp_set;
-+pa_cvolume_ramp_channel_ramp_set;
- pa_cvolume_remap;
- pa_cvolume_scale;
- pa_cvolume_scale_mask;
---- a/src/pulse/def.h 2016-04-12 15:05:58.245975421 +0200
-+++ b/src/pulse/def.h 2016-04-12 15:13:19.424974685 +0200
-@@ -347,11 +347,15 @@
- * consider absolute when the sink is in flat volume mode,
- * relative otherwise. \since 0.9.20 */
-
-- PA_STREAM_PASSTHROUGH = 0x80000U
-+ PA_STREAM_PASSTHROUGH = 0x80000U,
- /**< Used to tag content that will be rendered by passthrough sinks.
- * The data will be left as is and not reformatted, resampled.
- * \since 1.0 */
-
-+ PA_STREAM_START_RAMP_MUTED = 0x100000U
-+ /**< Used to tag content that the stream will be started ramp volume
-+ * muted so that you can nicely fade it in */
-+
- } pa_stream_flags_t;
-
- /** \cond fulldocs */
-@@ -380,6 +384,7 @@
- #define PA_STREAM_FAIL_ON_SUSPEND PA_STREAM_FAIL_ON_SUSPEND
- #define PA_STREAM_RELATIVE_VOLUME PA_STREAM_RELATIVE_VOLUME
- #define PA_STREAM_PASSTHROUGH PA_STREAM_PASSTHROUGH
-+#define PA_STREAM_START_RAMP_MUTED PA_STREAM_START_RAMP_MUTED
-
- /** \endcond */
-
-@@ -1047,6 +1052,13 @@
- /** \endcond */
- #endif
-
-+/** \cond fulldocs */
-+#define PA_VOLUMER_RAMP_TYPE_LINEAR PA_VOLUMER_RAMP_TYPE_LINEAR
-+#define PA_VOLUMER_RAMP_TYPE_LOGARITHMIC PA_VOLUMER_RAMP_TYPE_LOGARITHMIC
-+#define PA_VOLUMER_RAMP_TYPE_CUBIC PA_VOLUMER_RAMP_TYPE_CUBIC
-+
-+/** \endcond */
-+
- PA_C_DECL_END
-
- #endif
---- a/src/pulse/volume.c 2016-04-12 15:13:38.598974653 +0200
-+++ b/src/pulse/volume.c 2016-04-12 15:27:57.729973219 +0200
-@@ -445,7 +445,10 @@
- unsigned c;
- pa_assert(a);
-
-- pa_return_val_if_fail(pa_cvolume_valid(a), 0);
-+ if (pa_cvolume_valid(a) == 0)
-+ abort();
-+
-+ /* pa_return_val_if_fail(pa_cvolume_valid(a), 0); */
- pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0);
-
- for (c = 0; c < a->channels; c++)
-@@ -986,3 +989,51 @@
-
- return pa_cvolume_scale(v, m);
- }
-+
-+pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp) {
-+ unsigned c;
-+
-+ pa_assert(ramp);
-+
-+ ramp->channels = 0;
-+
-+ for (c = 0; c < PA_CHANNELS_MAX; c++) {
-+ ramp->ramps[c].type = PA_VOLUME_RAMP_TYPE_LINEAR;
-+ ramp->ramps[c].length = 0;
-+ ramp->ramps[c].target = PA_VOLUME_INVALID;
-+ }
-+
-+ return ramp;
-+}
-+
-+pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channels, pa_volume_ramp_type_t type, long time, pa_volume_t vol) {
-+ int i;
-+
-+ pa_assert(ramp);
-+ pa_assert(channels > 0);
-+ pa_assert(time >= 0);
-+ pa_assert(channels <= PA_CHANNELS_MAX);
-+
-+ ramp->channels = (uint8_t) channels;
-+
-+ for (i = 0; i < ramp->channels; i++) {
-+ ramp->ramps[i].type = type;
-+ ramp->ramps[i].length = time;
-+ ramp->ramps[i].target = PA_CLAMP_VOLUME(vol);
-+ }
-+
-+ return ramp;
-+}
-+
-+pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol) {
-+
-+ pa_assert(ramp);
-+ pa_assert(channel <= ramp->channels);
-+ pa_assert(time >= 0);
-+
-+ ramp->ramps[channel].type = type;
-+ ramp->ramps[channel].length = time;
-+ ramp->ramps[channel].target = PA_CLAMP_VOLUME(vol);
-+
-+ return ramp;
-+}
---- a/src/pulse/volume.h 2016-04-12 15:40:34.989971955 +0200
-+++ b/src/pulse/volume.h 2016-04-12 15:38:50.708972129 +0200
-@@ -413,6 +413,36 @@
- * the channels are kept. \since 0.9.16 */
- pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec);
-
-+/** Volume ramp type
-+*/
-+typedef enum pa_volume_ramp_type {
-+ PA_VOLUME_RAMP_TYPE_LINEAR = 0, /**< linear */
-+ PA_VOLUME_RAMP_TYPE_LOGARITHMIC = 1, /**< logarithmic */
-+ PA_VOLUME_RAMP_TYPE_CUBIC = 2,
-+} pa_volume_ramp_type_t;
-+
-+/** A structure encapsulating a volume ramp */
-+typedef struct pa_volume_ramp_t {
-+ pa_volume_ramp_type_t type;
-+ long length;
-+ pa_volume_t target;
-+} pa_volume_ramp_t;
-+
-+/** A structure encapsulating a multichannel volume ramp */
-+typedef struct pam_cvolume_ramp {
-+ uint8_t channels;
-+ pa_volume_ramp_t ramps[PA_CHANNELS_MAX];
-+} pa_cvolume_ramp;
-+
-+/** Init volume ramp struct */
-+pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp);
-+
-+/** Set first n channels of ramp struct to certain value */
-+pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol);
-+
-+/** Set individual channel in the channel struct */
-+pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol);
-+
- PA_C_DECL_END
-
- #endif
---- a/src/pulsecore/sample-util.c 2016-04-12 15:41:51.812971827 +0200
-+++ b/src/pulsecore/sample-util.c 2016-04-12 16:31:56.795966812 +0200
-@@ -41,6 +41,13 @@
-
- #define PA_SILENCE_MAX (PA_PAGE_SIZE*16)
-
-+#define VOLUME_PADDING 32
-+
-+typedef union {
-+ float f;
-+ uint32_t i;
-+} volume_val;
-+
- pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
- void *data;
-
-@@ -403,3 +410,292 @@
- usec = pa_bytes_to_usec_round_up(size, from);
- return pa_usec_to_bytes_round_up(usec, to);
- }
-+
-+static void calc_linear_integer_volume_no_mapping(int32_t linear[], float volume[], unsigned nchannels) {
-+ unsigned channel, padding;
-+
-+ pa_assert(linear);
-+ pa_assert(volume);
-+
-+ for (channel = 0; channel < nchannels; channel++)
-+ linear[channel] = (int32_t) lrint(volume[channel] * 0x10000U);
-+
-+ for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
-+ linear[channel] = linear[padding];
-+}
-+
-+static void calc_linear_float_volume_no_mapping(float linear[], float volume[], unsigned nchannels) {
-+ unsigned channel, padding;
-+
-+ pa_assert(linear);
-+ pa_assert(volume);
-+
-+ for (channel = 0; channel < nchannels; channel++)
-+ linear[channel] = volume[channel];
-+
-+ for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
-+ linear[channel] = linear[padding];
-+}
-+
-+typedef void (*pa_calc_volume_no_mapping_func_t) (void *volumes, float *volume, int channels);
-+
-+static const pa_calc_volume_no_mapping_func_t calc_volume_table_no_mapping[] = {
-+ [PA_SAMPLE_U8] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
-+ [PA_SAMPLE_ALAW] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
-+ [PA_SAMPLE_ULAW] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
-+ [PA_SAMPLE_S16LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
-+ [PA_SAMPLE_S16BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
-+ [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_float_volume_no_mapping,
-+ [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_float_volume_no_mapping,
-+ [PA_SAMPLE_S32LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
-+ [PA_SAMPLE_S32BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
-+ [PA_SAMPLE_S24LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
-+ [PA_SAMPLE_S24BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
-+ [PA_SAMPLE_S24_32LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping,
-+ [PA_SAMPLE_S24_32BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping
-+};
-+
-+static const unsigned format_sample_size_table[] = {
-+ [PA_SAMPLE_U8] = 1,
-+ [PA_SAMPLE_ALAW] = 1,
-+ [PA_SAMPLE_ULAW] = 1,
-+ [PA_SAMPLE_S16LE] = 2,
-+ [PA_SAMPLE_S16BE] = 2,
-+ [PA_SAMPLE_FLOAT32LE] = 4,
-+ [PA_SAMPLE_FLOAT32BE] = 4,
-+ [PA_SAMPLE_S32LE] = 4,
-+ [PA_SAMPLE_S32BE] = 4,
-+ [PA_SAMPLE_S24LE] = 3,
-+ [PA_SAMPLE_S24BE] = 3,
-+ [PA_SAMPLE_S24_32LE] = 4,
-+ [PA_SAMPLE_S24_32BE] = 4
-+};
-+
-+static float calc_volume_ramp_linear(pa_volume_ramp_int_t *ramp) {
-+ pa_assert(ramp);
-+ pa_assert(ramp->length > 0);
-+
-+ /* basic linear interpolation */
-+ return ramp->start + (ramp->length - ramp->left) * (ramp->end - ramp->start) / (float) ramp->length;
-+}
-+
-+static float calc_volume_ramp_logarithmic(pa_volume_ramp_int_t *ramp) {
-+ float x_val, s, e;
-+ long temp;
-+
-+ pa_assert(ramp);
-+ pa_assert(ramp->length > 0);
-+
-+ if (ramp->end > ramp->start) {
-+ temp = ramp->left;
-+ s = ramp->end;
-+ e = ramp->start;
-+ } else {
-+ temp = ramp->length - ramp->left;
-+ s = ramp->start;
-+ e = ramp->end;
-+ }
-+
-+ x_val = temp == 0 ? 0.0 : powf(temp, 10);
-+
-+ /* base 10 logarithmic interpolation */
-+ return s + x_val * (e - s) / powf(ramp->length, 10);
-+}
-+
-+static float calc_volume_ramp_cubic(pa_volume_ramp_int_t *ramp) {
-+ float x_val, s, e;
-+ long temp;
-+
-+ pa_assert(ramp);
-+ pa_assert(ramp->length > 0);
-+
-+ if (ramp->end > ramp->start) {
-+ temp = ramp->left;
-+ s = ramp->end;
-+ e = ramp->start;
-+ } else {
-+ temp = ramp->length - ramp->left;
-+ s = ramp->start;
-+ e = ramp->end;
-+ }
-+
-+ x_val = temp == 0 ? 0.0 : cbrtf(temp);
-+
-+ /* cubic interpolation */
-+ return s + x_val * (e - s) / cbrtf(ramp->length);
-+}
-+
-+typedef float (*pa_calc_volume_ramp_func_t) (pa_volume_ramp_int_t *);
-+
-+static const pa_calc_volume_ramp_func_t calc_volume_ramp_table[] = {
-+ [PA_VOLUME_RAMP_TYPE_LINEAR] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_linear,
-+ [PA_VOLUME_RAMP_TYPE_LOGARITHMIC] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_logarithmic,
-+ [PA_VOLUME_RAMP_TYPE_CUBIC] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_cubic
-+};
-+
-+static void calc_volume_ramps(pa_cvolume_ramp_int *ram, float *vol)
-+{
-+ int i;
-+
-+ for (i = 0; i < ram->channels; i++) {
-+ if (ram->ramps[i].left <= 0) {
-+ if (ram->ramps[i].target == PA_VOLUME_NORM) {
-+ vol[i] = 1.0;
-+ }
-+ } else {
-+ vol[i] = ram->ramps[i].curr = calc_volume_ramp_table[ram->ramps[i].type] (&ram->ramps[i]);
-+ ram->ramps[i].left--;
-+ }
-+ }
-+}
-+
-+void pa_volume_ramp_memchunk(
-+ pa_memchunk *c,
-+ const pa_sample_spec *spec,
-+ pa_cvolume_ramp_int *ramp) {
-+
-+ void *ptr;
-+ volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING];
-+ float vol[PA_CHANNELS_MAX + VOLUME_PADDING];
-+ pa_do_volume_func_t do_volume;
-+ long length_in_frames;
-+ int i;
-+
-+ pa_assert(c);
-+ pa_assert(spec);
-+ pa_assert(pa_frame_aligned(c->length, spec));
-+ pa_assert(ramp);
-+
-+ length_in_frames = c->length / format_sample_size_table[spec->format] / spec->channels;
-+
-+ if (pa_memblock_is_silence(c->memblock)) {
-+ for (i = 0; i < ramp->channels; i++) {
-+ if (ramp->ramps[i].length > 0)
-+ ramp->ramps[i].length -= length_in_frames;
-+ }
-+ return;
-+ }
-+
-+ if (spec->format < 0 || spec->format >= PA_SAMPLE_MAX) {
-+ pa_log_warn("Unable to change volume of format");
-+ return;
-+ }
-+
-+ do_volume = pa_get_volume_func(spec->format);
-+ pa_assert(do_volume);
-+
-+ ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index;
-+
-+ for (i = 0; i < length_in_frames; i++) {
-+ calc_volume_ramps(ramp, vol);
-+ calc_volume_table_no_mapping[spec->format] ((void *)linear, vol, spec->channels);
-+
-+ /* we only process one frame per iteration */
-+ do_volume (ptr, (void *)linear, spec->channels, format_sample_size_table[spec->format] * spec->channels);
-+
-+ /* pa_log_debug("1: %d 2: %d", linear[0], linear[1]); */
-+
-+ ptr = (uint8_t*)ptr + format_sample_size_table[spec->format] * spec->channels;
-+ }
-+
-+ pa_memblock_release(c->memblock);
-+}
-+
-+pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst, int sample_rate) {
-+ int i;
-+ float temp;
-+
-+ for (i = 0; i < dst->channels; i++) {
-+ dst->ramps[i].type = src->ramps[i].type;
-+ /* ms to samples */
-+ dst->ramps[i].length = src->ramps[i].length * sample_rate / 1000;
-+ dst->ramps[i].left = dst->ramps[i].length;
-+ dst->ramps[i].start = dst->ramps[i].end;
-+ dst->ramps[i].target = src->ramps[i].target;
-+ /* scale to pulse internal mapping so that when ramp is over there's no glitch in volume */
-+ temp = src->ramps[i].target / (float)0x10000U;
-+ dst->ramps[i].end = temp * temp * temp;
-+ }
-+
-+ return dst;
-+}
-+
-+bool pa_cvolume_ramp_active(pa_cvolume_ramp_int *ramp) {
-+ int i;
-+
-+ for (i = 0; i < ramp->channels; i++) {
-+ if (ramp->ramps[i].left > 0)
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+bool pa_cvolume_ramp_target_active(pa_cvolume_ramp_int *ramp) {
-+ int i;
-+
-+ for (i = 0; i < ramp->channels; i++) {
-+ if (ramp->ramps[i].target != PA_VOLUME_NORM)
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+pa_cvolume * pa_cvolume_ramp_get_targets(pa_cvolume_ramp_int *ramp, pa_cvolume *volume) {
-+ int i = 0;
-+
-+ volume->channels = ramp->channels;
-+
-+ for (i = 0; i < ramp->channels; i++)
-+ volume->values[i] = ramp->ramps[i].target;
-+
-+ return volume;
-+}
-+
-+pa_cvolume_ramp_int* pa_cvolume_ramp_start_from(pa_cvolume_ramp_int *src, pa_cvolume_ramp_int *dst) {
-+ int i;
-+
-+ for (i = 0; i < src->channels; i++) {
-+ /* if new vols are invalid, copy old ramp i.e. no effect */
-+ if (dst->ramps[i].target == PA_VOLUME_INVALID)
-+ dst->ramps[i] = src->ramps[i];
-+ /* if there's some old ramp still left */
-+ else if (src->ramps[i].left > 0)
-+ dst->ramps[i].start = src->ramps[i].curr;
-+ }
-+
-+ return dst;
-+}
-+
-+pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, int channels) {
-+ int i;
-+ float temp;
-+
-+ src->channels = channels;
-+
-+ for (i = 0; i < channels; i++) {
-+ src->ramps[i].type = PA_VOLUME_RAMP_TYPE_LINEAR;
-+ src->ramps[i].length = 0;
-+ src->ramps[i].left = 0;
-+ if (vol == PA_VOLUME_NORM) {
-+ src->ramps[i].start = 1.0;
-+ src->ramps[i].end = 1.0;
-+ src->ramps[i].curr = 1.0;
-+ }
-+ else if (vol == PA_VOLUME_MUTED) {
-+ src->ramps[i].start = 0.0;
-+ src->ramps[i].end = 0.0;
-+ src->ramps[i].curr = 0.0;
-+ }
-+ else {
-+ temp = vol / (float)0x10000U;
-+ src->ramps[i].start = temp * temp * temp;
-+ src->ramps[i].end = src->ramps[i].start;
-+ src->ramps[i].curr = src->ramps[i].start;
-+ }
-+ src->ramps[i].target = vol;
-+ }
-+
-+ return src;
-+}
---- a/src/pulsecore/sample-util.h 2016-04-12 15:53:06.327970701 +0200
-+++ b/src/pulsecore/sample-util.h 2016-04-12 16:24:16.356967580 +0200
-@@ -45,6 +45,33 @@
-
- pa_memchunk* pa_silence_memchunk_get(pa_silence_cache *cache, pa_mempool *pool, pa_memchunk* ret, const pa_sample_spec *spec, size_t length);
-
-+typedef struct pa_volume_ramp_int_t {
-+ pa_volume_ramp_type_t type;
-+ long length;
-+ long left;
-+ float start;
-+ float end;
-+ float curr;
-+ pa_volume_t target;
-+} pa_volume_ramp_int_t;
-+
-+typedef struct pa_cvolume_ramp_int {
-+ uint8_t channels;
-+ pa_volume_ramp_int_t ramps[PA_CHANNELS_MAX];
-+} pa_cvolume_ramp_int;
-+
-+pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst, int sample_rate);
-+bool pa_cvolume_ramp_active(pa_cvolume_ramp_int *ramp);
-+bool pa_cvolume_ramp_target_active(pa_cvolume_ramp_int *ramp);
-+pa_cvolume_ramp_int* pa_cvolume_ramp_start_from(pa_cvolume_ramp_int *src, pa_cvolume_ramp_int *dst);
-+pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, int channels);
-+pa_cvolume * pa_cvolume_ramp_get_targets(pa_cvolume_ramp_int *ramp, pa_cvolume *volume);
-+
-+void pa_volume_ramp_memchunk(
-+ pa_memchunk *c,
-+ const pa_sample_spec *spec,
-+ pa_cvolume_ramp_int *ramp);
-+
- size_t pa_frame_align(size_t l, const pa_sample_spec *ss) PA_GCC_PURE;
-
- bool pa_frame_aligned(size_t l, const pa_sample_spec *ss) PA_GCC_PURE;
diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0011-volume-ramp-adding-volume-ramping-to-sink-input.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0011-volume-ramp-adding-volume-ramping-to-sink-input.patch
deleted file mode 100644
index 08fb79248..000000000
--- a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0011-volume-ramp-adding-volume-ramping-to-sink-input.patch
+++ /dev/null
@@ -1,159 +0,0 @@
---- a/src/pulsecore/sink-input.c 2016-04-12 16:50:41.311964935 +0200
-+++ b/src/pulsecore/sink-input.c 2016-04-12 17:22:40.420961732 +0200
-@@ -525,6 +525,11 @@
- reset_callbacks(i);
- i->userdata = NULL;
-
-+ if (data->flags & PA_SINK_INPUT_START_RAMP_MUTED)
-+ pa_cvolume_ramp_int_init(&i->ramp, PA_VOLUME_MUTED, data->sample_spec.channels);
-+ else
-+ pa_cvolume_ramp_int_init(&i->ramp, PA_VOLUME_NORM, data->sample_spec.channels);
-+
- i->thread_info.state = i->state;
- i->thread_info.attached = false;
- pa_atomic_store(&i->thread_info.drained, 1);
-@@ -541,6 +546,8 @@
- i->thread_info.playing_for = 0;
- i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
-
-+ i->thread_info.ramp = i->ramp;
-+
- pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0);
- pa_assert_se(pa_idxset_put(i->sink->inputs, pa_sink_input_ref(i), NULL) == 0);
-
-@@ -922,6 +929,8 @@
- while (tchunk.length > 0) {
- pa_memchunk wchunk;
- bool nvfs = need_volume_factor_sink;
-+ pa_cvolume target;
-+ bool tmp;
-
- wchunk = tchunk;
- pa_memblock_ref(wchunk.memblock);
-@@ -958,6 +967,16 @@
- pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &i->volume_factor_sink);
- }
-
-+ /* check for possible volume ramp */
-+ if (pa_cvolume_ramp_active(&i->thread_info.ramp)) {
-+ pa_memchunk_make_writable(&wchunk, 0);
-+ pa_volume_ramp_memchunk(&wchunk, &i->sink->sample_spec, &(i->thread_info.ramp));
-+ } else if ((tmp = pa_cvolume_ramp_target_active(&(i->thread_info.ramp)))) {
-+ pa_memchunk_make_writable(&wchunk, 0);
-+ pa_cvolume_ramp_get_targets(&i->thread_info.ramp, &target);
-+ pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &target);
-+ }
-+
- pa_memblockq_push_align(i->thread_info.render_memblockq, &wchunk);
- } else {
- pa_memchunk rchunk;
-@@ -974,6 +993,16 @@
- pa_volume_memchunk(&rchunk, &i->sink->sample_spec, &i->volume_factor_sink);
- }
-
-+ /* check for possible volume ramp */
-+ if (pa_cvolume_ramp_active(&i->thread_info.ramp)) {
-+ pa_memchunk_make_writable(&wchunk, 0);
-+ pa_volume_ramp_memchunk(&wchunk, &i->sink->sample_spec, &(i->thread_info.ramp));
-+ } else if ((tmp = pa_cvolume_ramp_target_active(&(i->thread_info.ramp)))) {
-+ pa_memchunk_make_writable(&wchunk, 0);
-+ pa_cvolume_ramp_get_targets(&i->thread_info.ramp, &target);
-+ pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &target);
-+ }
-+
- pa_memblockq_push_align(i->thread_info.render_memblockq, &rchunk);
- pa_memblock_unref(rchunk.memblock);
- }
-@@ -1338,6 +1367,31 @@
- return 0;
- }
-
-+/* Called from main thread */
-+void pa_sink_input_set_volume_ramp(
-+ pa_sink_input *i,
-+ const pa_cvolume_ramp *ramp,
-+ bool send_msg,
-+ bool save) {
-+
-+ pa_sink_input_assert_ref(i);
-+ pa_assert_ctl_context();
-+ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
-+ pa_assert(ramp);
-+
-+ pa_cvolume_ramp_convert(ramp, &i->ramp, i->sample_spec.rate);
-+
-+ pa_log_debug("setting volume ramp with target vol:%d and length:%ld",
-+ i->ramp.ramps[0].target,
-+ i->ramp.ramps[0].length);
-+
-+
-+ /* This tells the sink that volume ramp changed */
-+ if (send_msg)
-+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP,
-+ NULL, 0, NULL) == 0);
-+}
-+
- /* Called from main context */
- static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) {
- pa_sink_input_assert_ref(i);
-@@ -1929,6 +1983,12 @@
- }
- return 0;
-
-+ case PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP:
-+ /* we have ongoing ramp where we take current start values */
-+ pa_cvolume_ramp_start_from(&i->thread_info.ramp, &i->ramp);
-+ i->thread_info.ramp = i->ramp;
-+ return 0;
-+
- case PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE:
- if (i->thread_info.muted != i->muted) {
- i->thread_info.muted = i->muted;
---- a/src/pulsecore/sink-input.h 2016-04-12 16:50:46.712964926 +0200
-+++ b/src/pulsecore/sink-input.h 2016-04-12 17:30:24.289960958 +0200
-@@ -59,7 +59,8 @@
- PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND = 256,
- PA_SINK_INPUT_NO_CREATE_ON_SUSPEND = 512,
- PA_SINK_INPUT_KILL_ON_SUSPEND = 1024,
-- PA_SINK_INPUT_PASSTHROUGH = 2048
-+ PA_SINK_INPUT_PASSTHROUGH = 2048,
-+ PA_SINK_INPUT_START_RAMP_MUTED = 4096,
- } pa_sink_input_flags_t;
-
- struct pa_sink_input {
-@@ -122,6 +123,9 @@
- * this.*/
- bool save_sink:1, save_volume:1, save_muted:1;
-
-+ /* for volume ramps */
-+ pa_cvolume_ramp_int ramp;
-+
- pa_resample_method_t requested_resample_method, actual_resample_method;
-
- /* Returns the chunk of audio data and drops it from the
-@@ -250,6 +254,8 @@
- pa_usec_t requested_sink_latency;
-
- pa_hashmap *direct_outputs;
-+
-+ pa_cvolume_ramp_int ramp;
- } thread_info;
-
- void *userdata;
-@@ -266,6 +272,7 @@
- PA_SINK_INPUT_MESSAGE_SET_STATE,
- PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY,
- PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY,
-+ PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP,
- PA_SINK_INPUT_MESSAGE_MAX
- };
-
-@@ -374,6 +381,8 @@
-
- void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save);
-
-+void pa_sink_input_set_volume_ramp(pa_sink_input *i, const pa_cvolume_ramp *ramp, bool send_msg, bool save);
-+
- void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p);
-
- pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i);
diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0012-volume-ramp-add-volume-ramping-to-sink.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0012-volume-ramp-add-volume-ramping-to-sink.patch
deleted file mode 100644
index 43e8283ef..000000000
--- a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0012-volume-ramp-add-volume-ramping-to-sink.patch
+++ /dev/null
@@ -1,159 +0,0 @@
---- a/src/pulsecore/sink.c 2016-04-12 18:01:23.403957855 +0200
-+++ b/src/pulsecore/sink.c 2016-04-12 18:44:49.677953506 +0200
-@@ -324,6 +324,8 @@
- &s->sample_spec,
- 0);
-
-+ pa_cvolume_ramp_int_init(&s->ramp, PA_VOLUME_NORM, data->sample_spec.channels);
-+
- s->thread_info.rtpoll = NULL;
- s->thread_info.inputs = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL,
- (pa_free_cb_t) pa_sink_input_unref);
-@@ -347,6 +349,8 @@
- s->thread_info.volume_change_extra_delay = core->deferred_volume_extra_delay_usec;
- s->thread_info.latency_offset = s->latency_offset;
-
-+ s->thread_info.ramp = s->ramp;
-+
- /* FIXME: This should probably be moved to pa_sink_put() */
- pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
-
-@@ -1182,6 +1186,7 @@
-
- } else if (n == 1) {
- pa_cvolume volume;
-+ pa_cvolume target;
-
- *result = info[0].chunk;
- pa_memblock_ref(result->memblock);
-@@ -1198,9 +1203,20 @@
- result,
- &s->sample_spec,
- result->length);
-- } else if (!pa_cvolume_is_norm(&volume)) {
-+ } else if (!pa_cvolume_is_norm(&volume) || pa_cvolume_ramp_target_active(&s->thread_info.ramp) || pa_cvolume_ramp_active(&s->thread_info.ramp)) {
- pa_memchunk_make_writable(result, 0);
-- pa_volume_memchunk(result, &s->sample_spec, &volume);
-+ if (!pa_cvolume_ramp_active(&s->thread_info.ramp)) {
-+ if (!pa_cvolume_is_norm(&volume))
-+ pa_volume_memchunk(result, &s->sample_spec, &volume);
-+ pa_volume_ramp_memchunk(result, &s->sample_spec, &(s->thread_info.ramp));
-+ }
-+ else {
-+ if (pa_cvolume_ramp_target_active(&s->thread_info.ramp)) {
-+ pa_cvolume_ramp_get_targets(&s->thread_info.ramp, &target);
-+ pa_sw_cvolume_multiply(&volume, &volume, &target);
-+ }
-+ pa_volume_memchunk(result, &s->sample_spec, &volume);
-+ }
- }
- } else {
- void *ptr;
-@@ -1290,6 +1306,7 @@
-
- } else {
- void *ptr;
-+ pa_cvolume target_vol;
-
- ptr = pa_memblock_acquire(target->memblock);
-
-@@ -1299,6 +1316,15 @@
- &s->thread_info.soft_volume,
- s->thread_info.soft_muted);
-
-+ if (pa_cvolume_ramp_target_active(&s->thread_info.ramp) || pa_cvolume_ramp_active(&s->thread_info.ramp)) {
-+ if (pa_cvolume_ramp_active(&s->thread_info.ramp))
-+ pa_volume_ramp_memchunk(target, &s->sample_spec, &(s->thread_info.ramp));
-+ else {
-+ pa_cvolume_ramp_get_targets(&s->thread_info.ramp, &target_vol);
-+ pa_volume_memchunk(target, &s->sample_spec, &target_vol);
-+ }
-+ }
-+
- pa_memblock_release(target->memblock);
- }
-
-@@ -2058,6 +2084,32 @@
- pa_assert_se(pa_asyncmsgq_send(root_sink->asyncmsgq, PA_MSGOBJECT(root_sink), PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL) == 0);
- }
-
-+/* Called from main thread */
-+void pa_sink_set_volume_ramp(
-+ pa_sink *s,
-+ const pa_cvolume_ramp *ramp,
-+ bool send_msg,
-+ bool save) {
-+
-+ pa_sink_assert_ref(s);
-+ pa_assert_ctl_context();
-+ pa_assert(PA_SINK_IS_LINKED(s->state));
-+ pa_assert(ramp);
-+
-+ /* make sure we don't change the volume when a PASSTHROUGH input is connected ...
-+ * ... *except* if we're being invoked to reset the volume to ensure 0 dB gain */
-+ if (pa_sink_is_passthrough(s)) {
-+ pa_log_warn("Cannot do volume ramp, Sink is connected to PASSTHROUGH input");
-+ return;
-+ }
-+
-+ pa_cvolume_ramp_convert(ramp, &s->ramp, s->sample_spec.rate);
-+
-+ /* This tells the sink that volume ramp changed */
-+ if (send_msg)
-+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME_RAMP, NULL, 0, NULL) == 0);
-+}
-+
- /* Called from the io thread if sync volume is used, otherwise from the main thread.
- * Only to be called by sink implementor */
- void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
-@@ -2713,6 +2765,12 @@
- sync_input_volumes_within_thread(s);
- return 0;
-
-+ case PA_SINK_MESSAGE_SET_VOLUME_RAMP:
-+ /* if we have ongoing ramp where we take current start values */
-+ pa_cvolume_ramp_start_from(&s->thread_info.ramp, &s->ramp);
-+ s->thread_info.ramp = s->ramp;
-+ return 0;
-+
- case PA_SINK_MESSAGE_GET_VOLUME:
-
- if ((s->flags & PA_SINK_DEFERRED_VOLUME) && s->get_volume) {
---- a/src/pulsecore/sink.h 2016-04-12 18:01:42.117957824 +0200
-+++ b/src/pulsecore/sink.h 2016-04-12 18:23:29.394955642 +0200
-@@ -105,6 +105,9 @@
- pa_cvolume saved_volume;
- bool saved_save_volume:1;
-
-+ /* for volume ramps */
-+ pa_cvolume_ramp_int ramp;
-+
- pa_asyncmsgq *asyncmsgq;
-
- pa_memchunk silence;
-@@ -300,6 +303,8 @@
- uint32_t volume_change_safety_margin;
- /* Usec delay added to all volume change events, may be negative. */
- int32_t volume_change_extra_delay;
-+
-+ pa_cvolume_ramp_int ramp;
- } thread_info;
-
- void *userdata;
-@@ -333,6 +338,7 @@
- PA_SINK_MESSAGE_SET_MAX_REQUEST,
- PA_SINK_MESSAGE_SET_PORT,
- PA_SINK_MESSAGE_UPDATE_VOLUME_AND_MUTE,
-+ PA_SINK_MESSAGE_SET_VOLUME_RAMP,
- PA_SINK_MESSAGE_SET_LATENCY_OFFSET,
- PA_SINK_MESSAGE_MAX
- } pa_sink_message_t;
-@@ -453,6 +459,8 @@
- void pa_sink_set_mute(pa_sink *sink, bool mute, bool save);
- bool pa_sink_get_mute(pa_sink *sink, bool force_refresh);
-
-+void pa_sink_set_volume_ramp(pa_sink *s, const pa_cvolume_ramp *ramp, bool send_msg, bool save);
-+
- bool pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p);
-
- int pa_sink_set_port(pa_sink *s, const char *name, bool save);
diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0013-add-internal-corking-state-for-sink-input.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0013-add-internal-corking-state-for-sink-input.patch
deleted file mode 100644
index cb68e26af..000000000
--- a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0013-add-internal-corking-state-for-sink-input.patch
+++ /dev/null
@@ -1,72 +0,0 @@
---- a/src/pulsecore/sink-input.c 2016-04-13 11:44:04.389999429 +0200
-+++ b/src/pulsecore/sink-input.c 2016-04-13 11:52:45.167998560 +0200
-@@ -786,6 +786,9 @@
- update_n_corked(i, state);
- i->state = state;
-
-+ i->corked = false;
-+ i->corked_internal = false;
-+
- /* We might need to update the sink's volume if we are in flat volume mode. */
- if (pa_sink_flat_volume_enabled(i->sink))
- pa_sink_set_volume(i->sink, NULL, false, i->save_volume);
-@@ -1493,13 +1496,38 @@
- }
- }
-
-+static void pa_sink_input_cork_really(pa_sink_input *i, bool b) {
-+ pa_sink_input_assert_ref(i);
-+ pa_assert_ctl_context();
-+ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
-+
-+ if (i->corked_internal == false && i->corked == false)
-+ b = false;
-+ else
-+ b = true;
-+
-+ sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING);
-+}
-+
- /* Called from main context */
- void pa_sink_input_cork(pa_sink_input *i, bool b) {
- pa_sink_input_assert_ref(i);
- pa_assert_ctl_context();
- pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
-
-- sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING);
-+ i->corked = b;
-+
-+ pa_sink_input_cork_really(i, b);
-+}
-+
-+void pa_sink_input_cork_internal(pa_sink_input *i, bool b) {
-+ pa_sink_input_assert_ref(i);
-+ pa_assert_ctl_context();
-+ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
-+
-+ i->corked_internal = b;
-+
-+ pa_sink_input_cork_really(i, b);
- }
-
- /* Called from main context */
---- a/src/pulsecore/sink-input.h 2016-04-13 11:44:28.035999390 +0200
-+++ b/src/pulsecore/sink-input.h 2016-04-13 11:53:56.325998441 +0200
-@@ -126,6 +126,9 @@
- /* for volume ramps */
- pa_cvolume_ramp_int ramp;
-
-+ bool corked;
-+ bool corked_internal;
-+
- pa_resample_method_t requested_resample_method, actual_resample_method;
-
- /* Returns the chunk of audio data and drops it from the
-@@ -357,6 +360,7 @@
- void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes, bool rewrite, bool flush, bool dont_rewind_render);
-
- void pa_sink_input_cork(pa_sink_input *i, bool b);
-+void pa_sink_input_cork_internal(pa_sink_input *i, bool b);
-
- int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate);
- int pa_sink_input_update_rate(pa_sink_input *i);
diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0020-core-util-Add-pa_join.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0020-core-util-Add-pa_join.patch
deleted file mode 100644
index 891a5b83a..000000000
--- a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0020-core-util-Add-pa_join.patch
+++ /dev/null
@@ -1,37 +0,0 @@
---- a/src/pulsecore/core-util.c 2016-04-13 16:17:33.314016929 +0200
-+++ b/src/pulsecore/core-util.c 2016-04-13 16:18:31.186016833 +0200
-@@ -1104,6 +1104,24 @@
- return pa_xstrndup(current, l);
- }
-
-+char *pa_join(const char * const *strings, unsigned n_strings, const char *delimiter) {
-+ pa_strbuf *buf;
-+ unsigned i;
-+
-+ pa_assert(strings || n_strings == 0);
-+
-+ buf = pa_strbuf_new();
-+
-+ for (i = 0; i < n_strings; i++) {
-+ if (i > 0 && delimiter)
-+ pa_strbuf_puts(buf, delimiter);
-+
-+ pa_strbuf_puts(buf, strings[i]);
-+ }
-+
-+ return pa_strbuf_tostring_free(buf);
-+}
-+
- PA_STATIC_TLS_DECLARE(signame, pa_xfree);
-
- /* Return the name of an UNIX signal. Similar to Solaris sig2str() */
---- a/src/pulsecore/core-util.h 2016-04-13 16:17:39.177016919 +0200
-+++ b/src/pulsecore/core-util.h 2016-04-13 16:19:09.141016769 +0200
-@@ -108,6 +108,7 @@
- char *pa_split(const char *c, const char*delimiters, const char **state);
- const char *pa_split_in_place(const char *c, const char*delimiters, int *n, const char **state);
- char *pa_split_spaces(const char *c, const char **state);
-+char *pa_join(const char * const *strings, unsigned n_strings, const char *delimiter);
-
- char *pa_strip_nl(char *s);
- char *pa_strip(char *s);
diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0021-dynarray-Add-pa_dynarray_get_raw_array.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0021-dynarray-Add-pa_dynarray_get_raw_array.patch
deleted file mode 100644
index 040913c8f..000000000
--- a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0021-dynarray-Add-pa_dynarray_get_raw_array.patch
+++ /dev/null
@@ -1,21 +0,0 @@
---- a/src/pulsecore/dynarray.c 2016-04-13 16:25:38.628016119 +0200
-+++ b/src/pulsecore/dynarray.c 2016-04-13 16:26:54.694015992 +0200
-@@ -91,3 +91,9 @@
-
- return array->n_entries;
- }
-+
-+void * const *pa_dynarray_get_raw_array(pa_dynarray *array) {
-+ pa_assert(array);
-+
-+ return array->data;
-+}
---- a/src/pulsecore/dynarray.h 2016-04-13 16:25:43.225016112 +0200
-+++ b/src/pulsecore/dynarray.h 2016-04-13 16:27:47.414015904 +0200
-@@ -52,5 +52,5 @@
- void *pa_dynarray_steal_last(pa_dynarray *array);
-
- unsigned pa_dynarray_size(pa_dynarray *array);
--
-+void * const *pa_dynarray_get_raw_array(pa_dynarray *array);
- #endif
diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0022-device-port-Add-pa_device_port.active.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0022-device-port-Add-pa_device_port.active.patch
deleted file mode 100644
index 4a8143f61..000000000
--- a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0022-device-port-Add-pa_device_port.active.patch
+++ /dev/null
@@ -1,198 +0,0 @@
---- a/src/pulsecore/core.h 2016-04-13 16:38:56.392014788 +0200
-+++ b/src/pulsecore/core.h 2016-04-13 16:41:50.331014498 +0200
-@@ -125,6 +125,7 @@
- PA_CORE_HOOK_CARD_PROFILE_ADDED,
- PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED,
- PA_CORE_HOOK_PORT_AVAILABLE_CHANGED,
-+ PA_CORE_HOOK_PORT_ACTIVE_CHANGED,
- PA_CORE_HOOK_PORT_LATENCY_OFFSET_CHANGED,
- PA_CORE_HOOK_MAX
- } pa_core_hook_t;
---- a/src/pulsecore/device-port.c 2016-04-13 16:39:37.411014719 +0200
-+++ b/src/pulsecore/device-port.c 2016-04-13 17:06:47.393011999 +0200
-@@ -175,6 +175,21 @@
- pa_hook_fire(&core->hooks[PA_CORE_HOOK_PORT_LATENCY_OFFSET_CHANGED], p);
- }
-
-+void pa_device_port_active_changed(pa_device_port *port, bool new_active) {
-+ bool old_active;
-+
-+ pa_assert(port);
-+
-+ old_active = port->active;
-+
-+ if (new_active == old_active)
-+ return;
-+
-+ port->active = new_active;
-+ pa_log_debug("Port %s %s.", port->name, new_active ? "activated" : "deactivated");
-+ pa_hook_fire(&port->core->hooks[PA_CORE_HOOK_PORT_ACTIVE_CHANGED], port);
-+}
-+
- pa_device_port *pa_device_port_find_best(pa_hashmap *ports)
- {
- void *state;
---- a/src/pulsecore/device-port.h 2016-04-13 16:39:51.603014696 +0200
-+++ b/src/pulsecore/device-port.h 2016-04-13 17:07:12.649011957 +0200
-@@ -46,6 +46,7 @@
-
- unsigned priority;
- pa_available_t available; /* PA_AVAILABLE_UNKNOWN, PA_AVAILABLE_NO or PA_AVAILABLE_YES */
-+ bool active;
-
- pa_proplist *proplist;
- pa_hashmap *profiles; /* Does not own the profiles */
---- a/src/pulsecore/sink.c 2016-04-13 16:40:11.131014663 +0200
-+++ b/src/pulsecore/sink.c 2016-04-13 17:14:30.963011225 +0200
-@@ -658,6 +658,9 @@
- else
- pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
-
-+ if (s->active_port)
-+ pa_device_port_active_changed(s->active_port, true);
-+
- pa_source_put(s->monitor_source);
-
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
-@@ -685,6 +688,9 @@
- if (linked)
- pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
-
-+ if (s->active_port)
-+ pa_device_port_active_changed(s->active_port, false);
-+
- if (s->state != PA_SINK_UNLINKED)
- pa_namereg_unregister(s->core, s->name);
- pa_idxset_remove_by_data(s->core->sinks, s, NULL);
-@@ -3297,6 +3303,7 @@
- /* Called from main context */
- int pa_sink_set_port(pa_sink *s, const char *name, bool save) {
- pa_device_port *port;
-+ pa_device_port *old_port;
- int ret;
-
- pa_sink_assert_ref(s);
-@@ -3313,11 +3320,15 @@
- if (!(port = pa_hashmap_get(s->ports, name)))
- return -PA_ERR_NOENTITY;
-
-- if (s->active_port == port) {
-+ old_port = s->active_port;
-+
-+ if (port == old_port) {
- s->save_port = s->save_port || save;
- return 0;
- }
-
-+ pa_device_port_active_changed(old_port, false);
-+
- if (s->flags & PA_SINK_DEFERRED_VOLUME) {
- struct sink_message_set_port msg = { .port = port, .ret = 0 };
- pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_PORT, &msg, 0, NULL) == 0);
-@@ -3326,17 +3337,26 @@
- else
- ret = s->set_port(s, port);
-
-- if (ret < 0)
-- return -PA_ERR_NOENTITY;
-+ if (ret < 0) {
-+ pa_log("Failed to set the port of sink %s from %s to %s.", s->name, old_port->name, port->name);
-+
-+ /* We don't know the real state of the device, but let's assume that
-+ * the old port is still active, because s->active_port is left to
-+ * point to the old port anyway. */
-+ pa_device_port_active_changed(old_port, true);
-+
-+ return ret;
-+ }
-
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-
-- pa_log_info("Changed port of sink %u \"%s\" to %s", s->index, s->name, port->name);
-+ pa_log_info("Changed port of sink %u \"%s\" from %s to %s", s->index, s->name, old_port->name, port->name);
-
- s->active_port = port;
- s->save_port = save;
-
- pa_sink_set_latency_offset(s, s->active_port->latency_offset);
-+ pa_device_port_active_changed(port, true);
-
- pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s);
-
---- a/src/pulsecore/source.c 2016-04-13 16:40:25.290014640 +0200
-+++ b/src/pulsecore/source.c 2016-04-13 17:21:26.051010533 +0200
-@@ -603,6 +603,9 @@
- else
- pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
-
-+ if (s->active_port)
-+ pa_device_port_active_changed(s->active_port, true);
-+
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
- pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
- }
-@@ -623,6 +626,9 @@
- if (linked)
- pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
-
-+ if (s->active_port)
-+ pa_device_port_active_changed(s->active_port, false);
-+
- if (s->state != PA_SOURCE_UNLINKED)
- pa_namereg_unregister(s->core, s->name);
- pa_idxset_remove_by_data(s->core->sources, s, NULL);
-@@ -2576,6 +2582,7 @@
- /* Called from main context */
- int pa_source_set_port(pa_source *s, const char *name, bool save) {
- pa_device_port *port;
-+ pa_device_port *old_port;
- int ret;
-
- pa_source_assert_ref(s);
-@@ -2592,11 +2599,15 @@
- if (!(port = pa_hashmap_get(s->ports, name)))
- return -PA_ERR_NOENTITY;
-
-- if (s->active_port == port) {
-+ old_port = s->active_port;
-+
-+ if (port == old_port) {
- s->save_port = s->save_port || save;
- return 0;
- }
-
-+ pa_device_port_active_changed(old_port, false);
-+
- if (s->flags & PA_SOURCE_DEFERRED_VOLUME) {
- struct source_message_set_port msg = { .port = port, .ret = 0 };
- pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_PORT, &msg, 0, NULL) == 0);
-@@ -2605,16 +2616,26 @@
- else
- ret = s->set_port(s, port);
-
-- if (ret < 0)
-- return -PA_ERR_NOENTITY;
-+ if (ret < 0) {
-+ pa_log("Failed to set the port of sink %s from %s to %s.", s->name, old_port->name, port->name);
-+
-+ /* We don't know the real state of the device, but let's assume that
-+ * the old port is still active, because s->active_port is left to
-+ * point to the old port anyway. */
-+ pa_device_port_active_changed(old_port, true);
-+
-+ return ret;
-+ }
-
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-
-- pa_log_info("Changed port of source %u \"%s\" to %s", s->index, s->name, port->name);
-+ pa_log_info("Changed port of source %u \"%s\" from %s to %s", s->index, s->name, old_port->name, port->name);
-
- s->active_port = port;
- s->save_port = save;
-
-+ pa_device_port_active_changed(port, true);
-+
- pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], s);
-
- return 0;
diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0030-volume-api-Add-libvolume-api.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0030-volume-api-Add-libvolume-api.patch
deleted file mode 100644
index b904ac315..000000000
--- a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0030-volume-api-Add-libvolume-api.patch
+++ /dev/null
@@ -1,6118 +0,0 @@
-From 0223ac3e092249c792bedcab2bf5dbaec443f960 Mon Sep 17 00:00:00 2001
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 21 May 2014 11:51:27 +0300
-Subject: [PATCH 1/1] volume-api: Add libvolume-api.so
-
-This library implements the "core" of the new volume system, which
-will be used by several modules.
-
-Change-Id: Ib25ada1392e83237a3908e6064ee0ad6dff7afaf
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- Makefile.am | 3 +
- src/Makefile.am | 19 +-
- src/map-file | 15 +
- src/modules/volume-api/audio-group.c | 448 +++++++++++++
- src/modules/volume-api/audio-group.h | 85 +++
- src/modules/volume-api/binding.c | 386 +++++++++++
- src/modules/volume-api/binding.h | 128 ++++
- src/modules/volume-api/bvolume.h | 43 ++
- src/modules/volume-api/device-creator.c | 1108 +++++++++++++++++++++++++++++++
- src/modules/volume-api/device-creator.h | 32 +
- src/modules/volume-api/device.c | 293 ++++++++
- src/modules/volume-api/device.h | 76 +++
- src/modules/volume-api/mute-control.c | 306 +++++++++
- src/modules/volume-api/mute-control.h | 102 +++
- src/modules/volume-api/sstream.c | 366 ++++++++++
- src/modules/volume-api/sstream.h | 108 +++
- src/modules/volume-api/stream-creator.c | 691 +++++++++++++++++++
- src/modules/volume-api/stream-creator.h | 32 +
- src/modules/volume-api/volume-api.c | 647 ++++++++++++++++++
- src/modules/volume-api/volume-api.h | 163 +++++
- src/modules/volume-api/volume-control.c | 363 ++++++++++
- src/modules/volume-api/volume-control.h | 112 ++++
- src/pulse/ext-volume-api.c | 275 ++++++++
- src/pulse/ext-volume-api.h | 68 ++
- 24 files changed, 5868 insertions(+), 1 deletion(-)
- create mode 100644 src/modules/volume-api/audio-group.c
- create mode 100644 src/modules/volume-api/audio-group.h
- create mode 100644 src/modules/volume-api/binding.c
- create mode 100644 src/modules/volume-api/binding.h
- create mode 100644 src/modules/volume-api/bvolume.h
- create mode 100644 src/modules/volume-api/device-creator.c
- create mode 100644 src/modules/volume-api/device-creator.h
- create mode 100644 src/modules/volume-api/device.c
- create mode 100644 src/modules/volume-api/device.h
- create mode 100644 src/modules/volume-api/mute-control.c
- create mode 100644 src/modules/volume-api/mute-control.h
- create mode 100644 src/modules/volume-api/sstream.c
- create mode 100644 src/modules/volume-api/sstream.h
- create mode 100644 src/modules/volume-api/stream-creator.c
- create mode 100644 src/modules/volume-api/stream-creator.h
- create mode 100644 src/modules/volume-api/volume-api.c
- create mode 100644 src/modules/volume-api/volume-api.h
- create mode 100644 src/modules/volume-api/volume-control.c
- create mode 100644 src/modules/volume-api/volume-control.h
- create mode 100644 src/pulse/ext-volume-api.c
- create mode 100644 src/pulse/ext-volume-api.h
-
-diff --git a/Makefile.am b/Makefile.am
-index 9431d4a..cf4a648 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -57,6 +57,9 @@
- moduledevinternal_DATA = src/pulse/internal.h src/pulse/client-conf.h src/pulse/fork-detect.h
- moduledevinternaldir = $(includedir)/pulsemodule/pulse
-
-+moduledevvolumeapi_DATA = $(top_srcdir)/src/modules/volume-api/*.h
-+moduledevvolumeapidir = $(includedir)/pulsemodule/modules/volume-api
-+
- if HAVE_GLIB20
- pkgconfig_DATA += \
- libpulse-mainloop-glib.pc
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 22b9b81..bc41dca 100644
---- a/src/Makefile.am 2016-04-13 15:51:34.439019531 +0200
-+++ b/src/Makefile.am 2016-04-13 15:53:03.721019382 +0200
-@@ -792,6 +792,7 @@
- pulse/ext-device-manager.h \
- pulse/ext-device-restore.h \
- pulse/ext-stream-restore.h \
-+ pulse/ext-volume-api.h \
- pulse/format.h \
- pulse/gccmacro.h \
- pulse/introspect.h \
-@@ -838,6 +839,7 @@
- pulse/ext-device-manager.c pulse/ext-device-manager.h \
- pulse/ext-device-restore.c pulse/ext-device-restore.h \
- pulse/ext-stream-restore.c pulse/ext-stream-restore.h \
-+ pulse/ext-volume-api.c pulse/ext-volume-api.h \
- pulse/format.c pulse/format.h \
- pulse/gccmacro.h \
- pulse/internal.h \
-@@ -1018,7 +1020,8 @@ modlibexec_LTLIBRARIES = \
- libprotocol-cli.la \
- libprotocol-simple.la \
- libprotocol-http.la \
-- libprotocol-native.la
-+ libprotocol-native.la \
-+ libvolume-api.la
-
- if HAVE_WEBRTC
- modlibexec_LTLIBRARIES += libwebrtc-util.la
-@@ -1065,6 +1068,20 @@ libprotocol_native_la_CFLAGS += $(DBUS_CFLAGS)
- libprotocol_native_la_LIBADD += $(DBUS_LIBS)
- endif
-
-+libvolume_api_la_SOURCES = \
-+ modules/volume-api/audio-group.c modules/volume-api/audio-group.h \
-+ modules/volume-api/binding.c modules/volume-api/binding.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/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
-+
- 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
-diff --git a/src/map-file b/src/map-file
-index fbf3f22..1f64a2f 100644
---- a/src/map-file
-+++ b/src/map-file
-@@ -172,6 +172,21 @@
- pa_ext_stream_restore_subscribe;
- pa_ext_stream_restore_test;
- pa_ext_stream_restore_write;
-+pa_ext_volume_api_balance_valid;
-+pa_ext_volume_api_bvolume_copy_balance;
-+pa_ext_volume_api_bvolume_get_left_right_balance;
-+pa_ext_volume_api_bvolume_get_rear_front_balance;
-+pa_ext_volume_api_bvolume_equal;
-+pa_ext_volume_api_bvolume_from_cvolume;
-+pa_ext_volume_api_bvolume_init_invalid;
-+pa_ext_volume_api_bvolume_init_mono;
-+pa_ext_volume_api_bvolume_remap;
-+pa_ext_volume_api_bvolume_reset_balance;
-+pa_ext_volume_api_bvolume_set_left_right_balance;
-+pa_ext_volume_api_bvolume_set_rear_front_balance;
-+pa_ext_volume_api_bvolume_snprint_balance;
-+pa_ext_volume_api_bvolume_to_cvolume;
-+pa_ext_volume_api_bvolume_valid;
- pa_format_info_copy;
- pa_format_info_free;
- pa_format_info_from_string;
-diff --git a/src/modules/volume-api/audio-group.c b/src/modules/volume-api/audio-group.c
-new file mode 100644
-index 0000000..76bfa69
---- /dev/null
-+++ b/src/modules/volume-api/audio-group.c
-@@ -0,0 +1,448 @@
-+/***
-+ 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, const char *description, pa_audio_group **group) {
-+ pa_audio_group *group_local;
-+ int r;
-+
-+ pa_assert(api);
-+ pa_assert(name);
-+ pa_assert(description);
-+ pa_assert(group);
-+
-+ group_local = pa_xnew0(pa_audio_group, 1);
-+ group_local->volume_api = api;
-+ group_local->index = pa_volume_api_allocate_audio_group_index(api);
-+
-+ r = pa_volume_api_register_name(api, name, true, &group_local->name);
-+ if (r < 0)
-+ goto fail;
-+
-+ group_local->description = pa_xstrdup(description);
-+ group_local->proplist = pa_proplist_new();
-+ group_local->volume_streams = pa_hashmap_new(NULL, NULL);
-+ group_local->mute_streams = pa_hashmap_new(NULL, NULL);
-+
-+ *group = group_local;
-+
-+ return 0;
-+
-+fail:
-+ pa_audio_group_free(group_local);
-+
-+ 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_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK], group);
-+
-+ pa_volume_api_remove_audio_group(group->volume_api, 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);
-+
-+ if (group->mute_control_binding) {
-+ pa_binding_free(group->mute_control_binding);
-+ group->mute_control_binding = NULL;
-+ }
-+
-+ if (group->volume_control_binding) {
-+ pa_binding_free(group->volume_control_binding);
-+ group->volume_control_binding = NULL;
-+ }
-+
-+ pa_audio_group_set_have_own_mute_control(group, false);
-+ pa_audio_group_set_have_own_volume_control(group, false);
-+
-+ if (group->mute_control) {
-+ pa_mute_control_remove_audio_group(group->mute_control, group);
-+ group->mute_control = NULL;
-+ }
-+
-+ if (group->volume_control) {
-+ pa_volume_control_remove_audio_group(group->volume_control, group);
-+ group->volume_control = NULL;
-+ }
-+}
-+
-+void pa_audio_group_free(pa_audio_group *group) {
-+ pa_assert(group);
-+
-+ if (!group->unlinked)
-+ 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);
-+}
-+
-+const char *pa_audio_group_get_name(pa_audio_group *group) {
-+ pa_assert(group);
-+
-+ return group->name;
-+}
-+
-+static int volume_control_set_volume_cb(pa_volume_control *control, const pa_bvolume *volume, bool set_volume,
-+ bool set_balance) {
-+ pa_audio_group *group;
-+ pas_stream *stream;
-+ void *state;
-+
-+ pa_assert(control);
-+ pa_assert(volume);
-+
-+ group = control->userdata;
-+
-+ PA_HASHMAP_FOREACH(stream, group->volume_streams, state) {
-+ if (stream->own_volume_control)
-+ pa_volume_control_set_volume(stream->own_volume_control, volume, set_volume, set_balance);
-+ }
-+
-+ return 0;
-+}
-+
-+static void volume_control_set_initial_volume_cb(pa_volume_control *control) {
-+ pa_audio_group *group;
-+ pas_stream *stream;
-+ void *state;
-+
-+ pa_assert(control);
-+
-+ group = control->userdata;
-+
-+ PA_HASHMAP_FOREACH(stream, group->volume_streams, state) {
-+ if (stream->own_volume_control)
-+ pa_volume_control_set_volume(stream->own_volume_control, &control->volume, true, true);
-+ }
-+}
-+
-+void pa_audio_group_set_have_own_volume_control(pa_audio_group *group, bool have) {
-+ pa_assert(group);
-+
-+ if (have == group->have_own_volume_control)
-+ return;
-+
-+ if (have) {
-+ pa_bvolume initial_volume;
-+
-+ if (group->volume_api->core->flat_volumes)
-+ /* Usually the initial volume should get overridden by some module
-+ * that manages audio group volume levels, but if there's no such
-+ * module, let's try to avoid too high volume in flat volume
-+ * mode. */
-+ pa_bvolume_init_mono(&initial_volume, 0.3 * PA_VOLUME_NORM);
-+ else
-+ pa_bvolume_init_mono(&initial_volume, PA_VOLUME_NORM);
-+
-+ pa_assert(!group->own_volume_control);
-+ group->own_volume_control = pa_volume_control_new(group->volume_api, "audio-group-volume-control",
-+ group->description, false, false);
-+ pa_volume_control_set_owner_audio_group(group->own_volume_control, group);
-+ group->own_volume_control->set_volume = volume_control_set_volume_cb;
-+ group->own_volume_control->userdata = group;
-+ pa_volume_control_put(group->own_volume_control, &initial_volume, volume_control_set_initial_volume_cb);
-+ } else {
-+ pa_volume_control_free(group->own_volume_control);
-+ group->own_volume_control = NULL;
-+ }
-+
-+ group->have_own_volume_control = have;
-+}
-+
-+static int mute_control_set_mute_cb(pa_mute_control *control, bool mute) {
-+ pa_audio_group *group;
-+ pas_stream *stream;
-+ void *state;
-+
-+ pa_assert(control);
-+
-+ group = control->userdata;
-+
-+ PA_HASHMAP_FOREACH(stream, group->mute_streams, state) {
-+ if (stream->own_mute_control)
-+ pa_mute_control_set_mute(stream->own_mute_control, mute);
-+ }
-+
-+ return 0;
-+}
-+
-+static void mute_control_set_initial_mute_cb(pa_mute_control *control) {
-+ pa_audio_group *group;
-+ pas_stream *stream;
-+ void *state;
-+
-+ pa_assert(control);
-+
-+ group = control->userdata;
-+
-+ PA_HASHMAP_FOREACH(stream, group->mute_streams, state) {
-+ if (stream->own_mute_control)
-+ pa_mute_control_set_mute(stream->own_mute_control, control->mute);
-+ }
-+}
-+
-+void pa_audio_group_set_have_own_mute_control(pa_audio_group *group, bool have) {
-+ pa_assert(group);
-+
-+ if (have == group->have_own_mute_control)
-+ return;
-+
-+ group->have_own_mute_control = have;
-+
-+ if (have) {
-+ pa_assert(!group->own_mute_control);
-+ group->own_mute_control = pa_mute_control_new(group->volume_api, "audio-group-mute-control", group->description);
-+ pa_mute_control_set_owner_audio_group(group->own_mute_control, group);
-+ group->own_mute_control->set_mute = mute_control_set_mute_cb;
-+ group->own_mute_control->userdata = group;
-+ pa_mute_control_put(group->own_mute_control, false, true, mute_control_set_initial_mute_cb);
-+ } else {
-+ pa_mute_control_free(group->own_mute_control);
-+ group->own_mute_control = NULL;
-+ }
-+}
-+
-+static void set_volume_control_internal(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;
-+
-+ if (old_control)
-+ pa_volume_control_remove_audio_group(old_control, group);
-+
-+ group->volume_control = control;
-+
-+ if (control)
-+ pa_volume_control_add_audio_group(control, group);
-+
-+ 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_volume_control(pa_audio_group *group, pa_volume_control *control) {
-+ pa_assert(group);
-+
-+ if (group->volume_control_binding) {
-+ pa_binding_free(group->volume_control_binding);
-+ group->volume_control_binding = NULL;
-+ }
-+
-+ set_volume_control_internal(group, control);
-+}
-+
-+static void set_mute_control_internal(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;
-+
-+ if (old_control)
-+ pa_mute_control_remove_audio_group(old_control, group);
-+
-+ group->mute_control = control;
-+
-+ if (control)
-+ pa_mute_control_add_audio_group(control, group);
-+
-+ 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_set_mute_control(pa_audio_group *group, pa_mute_control *control) {
-+ pa_assert(group);
-+
-+ if (group->mute_control_binding) {
-+ pa_binding_free(group->mute_control_binding);
-+ group->mute_control_binding = NULL;
-+ }
-+
-+ set_mute_control_internal(group, control);
-+}
-+
-+void pa_audio_group_bind_volume_control(pa_audio_group *group, pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = group,
-+ .set_value = (pa_binding_set_value_cb_t) set_volume_control_internal,
-+ };
-+
-+ pa_assert(group);
-+ pa_assert(target_info);
-+
-+ if (group->volume_control_binding)
-+ pa_binding_free(group->volume_control_binding);
-+
-+ group->volume_control_binding = pa_binding_new(group->volume_api, &owner_info, target_info);
-+}
-+
-+void pa_audio_group_bind_mute_control(pa_audio_group *group, pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = group,
-+ .set_value = (pa_binding_set_value_cb_t) set_mute_control_internal,
-+ };
-+
-+ pa_assert(group);
-+ pa_assert(target_info);
-+
-+ if (group->mute_control_binding)
-+ pa_binding_free(group->mute_control_binding);
-+
-+ group->mute_control_binding = pa_binding_new(group->volume_api, &owner_info, target_info);
-+}
-+
-+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);
-+
-+ if (stream->own_volume_control && group->own_volume_control)
-+ pa_volume_control_set_volume(stream->own_volume_control, &group->own_volume_control->volume, true, true);
-+
-+ pa_log_debug("Stream %s added to audio group %s (volume).", stream->name, group->name);
-+}
-+
-+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));
-+
-+ pa_log_debug("Stream %s removed from audio group %s (volume).", stream->name, group->name);
-+}
-+
-+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);
-+
-+ if (stream->own_mute_control && group->own_mute_control)
-+ pa_mute_control_set_mute(stream->own_mute_control, group->own_mute_control->mute);
-+
-+ pa_log_debug("Stream %s added to audio group %s (mute).", stream->name, group->name);
-+}
-+
-+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));
-+
-+ pa_log_debug("Stream %s removed from audio group %s (mute).", stream->name, group->name);
-+}
-+
-+pa_binding_target_type *pa_audio_group_create_binding_target_type(pa_volume_api *api) {
-+ pa_binding_target_type *type;
-+
-+ pa_assert(api);
-+
-+ type = pa_binding_target_type_new(PA_AUDIO_GROUP_BINDING_TARGET_TYPE, api->audio_groups,
-+ &api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_PUT],
-+ &api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK],
-+ (pa_binding_target_type_get_name_cb_t) pa_audio_group_get_name);
-+ pa_binding_target_type_add_field(type, PA_AUDIO_GROUP_BINDING_TARGET_FIELD_VOLUME_CONTROL,
-+ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_audio_group, volume_control));
-+ pa_binding_target_type_add_field(type, PA_AUDIO_GROUP_BINDING_TARGET_FIELD_MUTE_CONTROL,
-+ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_audio_group, mute_control));
-+
-+ return type;
-+}
-diff --git a/src/modules/volume-api/audio-group.h b/src/modules/volume-api/audio-group.h
-new file mode 100644
-index 0000000..41591ba
---- /dev/null
-+++ b/src/modules/volume-api/audio-group.h
-@@ -0,0 +1,85 @@
-+#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/binding.h>
-+#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;
-+
-+#define PA_AUDIO_GROUP_BINDING_TARGET_TYPE "AudioGroup"
-+#define PA_AUDIO_GROUP_BINDING_TARGET_FIELD_VOLUME_CONTROL "volume_control"
-+#define PA_AUDIO_GROUP_BINDING_TARGET_FIELD_MUTE_CONTROL "mute_control"
-+
-+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;
-+ bool have_own_volume_control;
-+ bool have_own_mute_control;
-+ pa_volume_control *own_volume_control;
-+ pa_mute_control *own_mute_control;
-+
-+ pa_binding *volume_control_binding;
-+ pa_binding *mute_control_binding;
-+ 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, const char *description, pa_audio_group **group);
-+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);
-+
-+const char *pa_audio_group_get_name(pa_audio_group *group);
-+
-+/* Called by policy modules. */
-+void pa_audio_group_set_have_own_volume_control(pa_audio_group *group, bool have);
-+void pa_audio_group_set_have_own_mute_control(pa_audio_group *group, bool have);
-+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);
-+void pa_audio_group_bind_volume_control(pa_audio_group *group, pa_binding_target_info *target_info);
-+void pa_audio_group_bind_mute_control(pa_audio_group *group, pa_binding_target_info *target_info);
-+
-+/* Called from sstream.c only. */
-+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);
-+
-+/* Called from volume-api.c only. */
-+pa_binding_target_type *pa_audio_group_create_binding_target_type(pa_volume_api *api);
-+
-+#endif
-diff --git a/src/modules/volume-api/binding.c b/src/modules/volume-api/binding.c
-new file mode 100644
-index 0000000..6e73119
---- /dev/null
-+++ b/src/modules/volume-api/binding.c
-@@ -0,0 +1,386 @@
-+/***
-+ 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 "binding.h"
-+
-+#include <pulse/def.h>
-+#include <pulse/xmalloc.h>
-+
-+#include <pulsecore/core-util.h>
-+#include <pulsecore/macro.h>
-+
-+struct field_entry {
-+ char *name;
-+ size_t offset;
-+};
-+
-+static void set_target_type(pa_binding *binding, pa_binding_target_type *type);
-+static void set_target_object(pa_binding *binding, void *object);
-+
-+pa_binding_owner_info *pa_binding_owner_info_new(pa_binding_set_value_cb_t set_value, void *userdata) {
-+ pa_binding_owner_info *info;
-+
-+ pa_assert(set_value);
-+
-+ info = pa_xnew0(pa_binding_owner_info, 1);
-+ info->set_value = set_value;
-+ info->userdata = userdata;
-+
-+ return info;
-+}
-+
-+pa_binding_owner_info *pa_binding_owner_info_copy(const pa_binding_owner_info *info) {
-+ pa_assert(info);
-+
-+ return pa_binding_owner_info_new(info->set_value, info->userdata);
-+}
-+
-+void pa_binding_owner_info_free(pa_binding_owner_info *info) {
-+ pa_assert(info);
-+
-+ pa_xfree(info);
-+}
-+
-+pa_binding_target_info *pa_binding_target_info_new(const char *type, const char *name, const char *field) {
-+ pa_binding_target_info *info;
-+
-+ pa_assert(type);
-+ pa_assert(name);
-+ pa_assert(field);
-+
-+ info = pa_xnew0(pa_binding_target_info, 1);
-+ info->type = pa_xstrdup(type);
-+ info->name = pa_xstrdup(name);
-+ info->field = pa_xstrdup(field);
-+
-+ return info;
-+}
-+
-+int pa_binding_target_info_new_from_string(const char *str, const char *field, pa_binding_target_info **info) {
-+ const char *colon;
-+ char *type = NULL;
-+ char *name = NULL;
-+
-+ pa_assert(str);
-+ pa_assert(field);
-+ pa_assert(info);
-+
-+ if (!pa_startswith(str, "bind:"))
-+ goto fail;
-+
-+ colon = strchr(str + 5, ':');
-+ if (!colon)
-+ goto fail;
-+
-+ type = pa_xstrndup(str + 5, colon - (str + 5));
-+
-+ if (!*type)
-+ goto fail;
-+
-+ name = pa_xstrdup(colon + 1);
-+
-+ if (!*name)
-+ goto fail;
-+
-+ *info = pa_binding_target_info_new(type, name, field);
-+ pa_xfree(name);
-+ pa_xfree(type);
-+
-+ return 0;
-+
-+fail:
-+ pa_log("Invalid binding target: %s", str);
-+ pa_xfree(name);
-+ pa_xfree(type);
-+
-+ return -PA_ERR_INVALID;
-+}
-+
-+pa_binding_target_info *pa_binding_target_info_copy(const pa_binding_target_info *info) {
-+ pa_assert(info);
-+
-+ return pa_binding_target_info_new(info->type, info->name, info->field);
-+}
-+
-+void pa_binding_target_info_free(pa_binding_target_info *info) {
-+ pa_assert(info);
-+
-+ pa_xfree(info->field);
-+ pa_xfree(info->name);
-+ pa_xfree(info->type);
-+ pa_xfree(info);
-+}
-+
-+static void field_entry_free(struct field_entry *entry) {
-+ pa_assert(entry);
-+
-+ pa_xfree(entry->name);
-+ pa_xfree(entry);
-+}
-+
-+pa_binding_target_type *pa_binding_target_type_new(const char *name, pa_hashmap *objects, pa_hook *put_hook,
-+ pa_hook *unlink_hook, pa_binding_target_type_get_name_cb_t get_name) {
-+ pa_binding_target_type *type;
-+
-+ pa_assert(name);
-+ pa_assert(objects);
-+ pa_assert(put_hook);
-+ pa_assert(unlink_hook);
-+ pa_assert(get_name);
-+
-+ type = pa_xnew0(pa_binding_target_type, 1);
-+ type->name = pa_xstrdup(name);
-+ type->objects = objects;
-+ type->put_hook = put_hook;
-+ type->unlink_hook = unlink_hook;
-+ type->get_name = get_name;
-+ type->fields = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) field_entry_free);
-+
-+ return type;
-+}
-+
-+void pa_binding_target_type_free(pa_binding_target_type *type) {
-+ pa_assert(type);
-+
-+ if (type->fields)
-+ pa_hashmap_free(type->fields);
-+
-+ pa_xfree(type->name);
-+ pa_xfree(type);
-+}
-+
-+void pa_binding_target_type_add_field(pa_binding_target_type *type, const char *name, size_t offset) {
-+ struct field_entry *entry;
-+
-+ pa_assert(type);
-+ pa_assert(name);
-+
-+ entry = pa_xnew0(struct field_entry, 1);
-+ entry->name = pa_xstrdup(name);
-+ entry->offset = offset;
-+
-+ pa_assert_se(pa_hashmap_put(type->fields, entry->name, entry) >= 0);
-+}
-+
-+int pa_binding_target_type_get_field_offset(pa_binding_target_type *type, const char *field, size_t *offset) {
-+ struct field_entry *entry;
-+
-+ pa_assert(type);
-+ pa_assert(field);
-+ pa_assert(offset);
-+
-+ entry = pa_hashmap_get(type->fields, field);
-+ if (!entry)
-+ return -PA_ERR_NOENTITY;
-+
-+ *offset = entry->offset;
-+
-+ return 0;
-+}
-+
-+static pa_hook_result_t target_type_added_cb(void *hook_data, void *call_data, void *userdata) {
-+ pa_binding_target_type *type = call_data;
-+ pa_binding *binding = userdata;
-+
-+ pa_assert(type);
-+ pa_assert(binding);
-+
-+ if (!pa_streq(type->name, binding->target_info->type))
-+ return PA_HOOK_OK;
-+
-+ set_target_type(binding, type);
-+
-+ return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t target_type_removed_cb(void *hook_data, void *call_data, void *userdata) {
-+ pa_binding_target_type *type = call_data;
-+ pa_binding *binding = userdata;
-+
-+ pa_assert(type);
-+ pa_assert(binding);
-+
-+ if (type != binding->target_type)
-+ return PA_HOOK_OK;
-+
-+ set_target_type(binding, NULL);
-+
-+ return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t target_put_cb(void *hook_data, void *call_data, void *userdata) {
-+ pa_binding *binding = userdata;
-+
-+ pa_assert(call_data);
-+ pa_assert(binding);
-+
-+ if (!pa_streq(binding->target_type->get_name(call_data), binding->target_info->name))
-+ return PA_HOOK_OK;
-+
-+ set_target_object(binding, call_data);
-+
-+ return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t target_unlink_cb(void *hook_data, void *call_data, void *userdata) {
-+ pa_binding *binding = userdata;
-+
-+ pa_assert(call_data);
-+ pa_assert(binding);
-+
-+ if (call_data != binding->target_object)
-+ return PA_HOOK_OK;
-+
-+ set_target_object(binding, NULL);
-+
-+ return PA_HOOK_OK;
-+}
-+
-+static void set_target_object(pa_binding *binding, void *object) {
-+ pa_assert(binding);
-+
-+ binding->target_object = object;
-+
-+ if (object) {
-+ if (binding->target_put_slot) {
-+ pa_hook_slot_free(binding->target_put_slot);
-+ binding->target_put_slot = NULL;
-+ }
-+
-+ if (!binding->target_unlink_slot)
-+ binding->target_unlink_slot = pa_hook_connect(binding->target_type->unlink_hook, PA_HOOK_NORMAL, target_unlink_cb,
-+ binding);
-+
-+ if (binding->target_field_offset_valid)
-+ binding->owner_info->set_value(binding->owner_info->userdata,
-+ *((void **) (((uint8_t *) object) + binding->target_field_offset)));
-+ else
-+ binding->owner_info->set_value(binding->owner_info->userdata, NULL);
-+ } else {
-+ if (binding->target_unlink_slot) {
-+ pa_hook_slot_free(binding->target_unlink_slot);
-+ binding->target_unlink_slot = NULL;
-+ }
-+
-+ if (binding->target_type) {
-+ if (!binding->target_put_slot)
-+ binding->target_put_slot = pa_hook_connect(binding->target_type->put_hook, PA_HOOK_NORMAL, target_put_cb, binding);
-+ } else {
-+ if (binding->target_put_slot) {
-+ pa_hook_slot_free(binding->target_put_slot);
-+ binding->target_put_slot = NULL;
-+ }
-+ }
-+
-+ binding->owner_info->set_value(binding->owner_info->userdata, NULL);
-+ }
-+}
-+
-+static void set_target_type(pa_binding *binding, pa_binding_target_type *type) {
-+ pa_assert(binding);
-+
-+ binding->target_type = type;
-+
-+ if (type) {
-+ int r;
-+
-+ if (binding->target_type_added_slot) {
-+ pa_hook_slot_free(binding->target_type_added_slot);
-+ binding->target_type_added_slot = NULL;
-+ }
-+
-+ if (!binding->target_type_removed_slot)
-+ binding->target_type_removed_slot =
-+ pa_hook_connect(&binding->volume_api->hooks[PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_REMOVED],
-+ PA_HOOK_NORMAL, target_type_removed_cb, binding);
-+
-+ r = pa_binding_target_type_get_field_offset(type, binding->target_info->field, &binding->target_field_offset);
-+ if (r >= 0)
-+ binding->target_field_offset_valid = true;
-+ else {
-+ pa_log_warn("Reference to non-existing field \"%s\" in binding target type \"%s\".", binding->target_info->field,
-+ type->name);
-+ binding->target_field_offset_valid = false;
-+ }
-+
-+ set_target_object(binding, pa_hashmap_get(type->objects, binding->target_info->name));
-+ } else {
-+ if (binding->target_type_removed_slot) {
-+ pa_hook_slot_free(binding->target_type_removed_slot);
-+ binding->target_type_removed_slot = NULL;
-+ }
-+
-+ if (!binding->target_type_added_slot)
-+ binding->target_type_added_slot =
-+ pa_hook_connect(&binding->volume_api->hooks[PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_ADDED],
-+ PA_HOOK_NORMAL, target_type_added_cb, binding);
-+
-+ binding->target_field_offset_valid = false;
-+
-+ set_target_object(binding, NULL);
-+ }
-+}
-+
-+pa_binding *pa_binding_new(pa_volume_api *api, const pa_binding_owner_info *owner_info,
-+ const pa_binding_target_info *target_info) {
-+ pa_binding *binding;
-+
-+ pa_assert(api);
-+ pa_assert(owner_info);
-+ pa_assert(target_info);
-+
-+ binding = pa_xnew0(pa_binding, 1);
-+ binding->volume_api = api;
-+ binding->owner_info = pa_binding_owner_info_copy(owner_info);
-+ binding->target_info = pa_binding_target_info_copy(target_info);
-+
-+ set_target_type(binding, pa_hashmap_get(api->binding_target_types, target_info->type));
-+
-+ return binding;
-+}
-+
-+void pa_binding_free(pa_binding *binding) {
-+ pa_assert(binding);
-+
-+ if (binding->target_unlink_slot)
-+ pa_hook_slot_free(binding->target_unlink_slot);
-+
-+ if (binding->target_put_slot)
-+ pa_hook_slot_free(binding->target_put_slot);
-+
-+ if (binding->target_type_removed_slot)
-+ pa_hook_slot_free(binding->target_type_removed_slot);
-+
-+ if (binding->target_type_added_slot)
-+ pa_hook_slot_free(binding->target_type_added_slot);
-+
-+ if (binding->target_info)
-+ pa_binding_target_info_free(binding->target_info);
-+
-+ if (binding->owner_info)
-+ pa_binding_owner_info_free(binding->owner_info);
-+
-+ pa_xfree(binding);
-+}
-diff --git a/src/modules/volume-api/binding.h b/src/modules/volume-api/binding.h
-new file mode 100644
-index 0000000..ba4dea8
---- /dev/null
-+++ b/src/modules/volume-api/binding.h
-@@ -0,0 +1,128 @@
-+#ifndef foobindinghfoo
-+#define foobindinghfoo
-+
-+/***
-+ 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_binding pa_binding;
-+typedef struct pa_binding_owner_info pa_binding_owner_info;
-+typedef struct pa_binding_target_info pa_binding_target_info;
-+typedef struct pa_binding_target_type pa_binding_target_type;
-+
-+typedef void (*pa_binding_set_value_cb_t)(void *userdata, void *value);
-+
-+struct pa_binding_owner_info {
-+ /* This is the object that has the variable that the binding is created
-+ * for. */
-+ void *userdata;
-+
-+ /* Called when the owner object's value needs to be updated. The userdata
-+ * parameter of the callback is the same as the userdata field in this
-+ * struct, and the value parameter is the new value for whatever variable
-+ * the binding was created for. */
-+ pa_binding_set_value_cb_t set_value;
-+};
-+
-+pa_binding_owner_info *pa_binding_owner_info_new(pa_binding_set_value_cb_t set_value, void *userdata);
-+pa_binding_owner_info *pa_binding_owner_info_copy(const pa_binding_owner_info *info);
-+void pa_binding_owner_info_free(pa_binding_owner_info *info);
-+
-+struct pa_binding_target_info {
-+ /* The target type name as registered with
-+ * pa_binding_target_type_register(). */
-+ char *type;
-+
-+ /* The target object name as returned by the get_name callback of
-+ * pa_binding_target_type. */
-+ char *name;
-+
-+ /* The target field of the target object. */
-+ char *field;
-+};
-+
-+pa_binding_target_info *pa_binding_target_info_new(const char *type, const char *name, const char *field);
-+
-+/* The string format is "bind:TYPE:NAME". */
-+int pa_binding_target_info_new_from_string(const char *str, const char *field, pa_binding_target_info **info);
-+
-+pa_binding_target_info *pa_binding_target_info_copy(const pa_binding_target_info *info);
-+void pa_binding_target_info_free(pa_binding_target_info *info);
-+
-+typedef const char *(*pa_binding_target_type_get_name_cb_t)(void *object);
-+
-+struct pa_binding_target_type {
-+ /* Identifier for this target type. */
-+ char *name;
-+
-+ /* name -> object. Points directly to some "master" object hashmap, so the
-+ * hashmap is not owned by pa_binding_target_type. */
-+ pa_hashmap *objects;
-+
-+ /* The hook that notifies of new objects if this target type. The call data
-+ * of the hook must be a pointer to the new object (this should be true for
-+ * all PUT hooks, so don't worry too much). */
-+ pa_hook *put_hook;
-+
-+ /* The hook that notifies of unlinked objects of this target type. The call
-+ * data of the hook must be a pointer to the removed object (this should be
-+ * true for all UNLINK hooks, so don't worry too much). */
-+ pa_hook *unlink_hook;
-+
-+ /* Function for getting the name of an object of this target type. */
-+ pa_binding_target_type_get_name_cb_t get_name;
-+
-+ pa_hashmap *fields;
-+};
-+
-+pa_binding_target_type *pa_binding_target_type_new(const char *name, pa_hashmap *objects, pa_hook *put_hook,
-+ pa_hook *unlink_hook, pa_binding_target_type_get_name_cb_t get_name);
-+void pa_binding_target_type_free(pa_binding_target_type *type);
-+
-+/* Useful when calling pa_binding_target_type_add_field(). */
-+#define PA_BINDING_CALCULATE_FIELD_OFFSET(type, field) ((size_t) &(((type *) 0)->field))
-+
-+/* Called during the type initialization (right after
-+ * pa_binding_target_type_new()). */
-+void pa_binding_target_type_add_field(pa_binding_target_type *type, const char *name, size_t offset);
-+
-+int pa_binding_target_type_get_field_offset(pa_binding_target_type *type, const char *field, size_t *offset);
-+
-+struct pa_binding {
-+ pa_volume_api *volume_api;
-+ pa_binding_owner_info *owner_info;
-+ pa_binding_target_info *target_info;
-+ pa_binding_target_type *target_type;
-+ void *target_object;
-+ size_t target_field_offset;
-+ bool target_field_offset_valid;
-+ pa_hook_slot *target_type_added_slot;
-+ pa_hook_slot *target_type_removed_slot;
-+ pa_hook_slot *target_put_slot;
-+ pa_hook_slot *target_unlink_slot;
-+};
-+
-+pa_binding *pa_binding_new(pa_volume_api *api, const pa_binding_owner_info *owner_info,
-+ const pa_binding_target_info *target_info);
-+void pa_binding_free(pa_binding *binding);
-+
-+#endif
-diff --git a/src/modules/volume-api/bvolume.h b/src/modules/volume-api/bvolume.h
-new file mode 100644
-index 0000000..0317fb6
---- /dev/null
-+++ b/src/modules/volume-api/bvolume.h
-@@ -0,0 +1,43 @@
-+#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_mono pa_ext_volume_api_bvolume_init_mono
-+#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_SNPRINT_BALANCE_MAX PA_EXT_VOLUME_API_BVOLUME_SNPRINT_BALANCE_MAX
-+#define pa_bvolume_snprint_balance pa_ext_volume_api_bvolume_snprint_balance
-+
-+#endif
-diff --git a/src/modules/volume-api/device-creator.c b/src/modules/volume-api/device-creator.c
-new file mode 100644
-index 0000000..1d912ba
---- /dev/null
-+++ b/src/modules/volume-api/device-creator.c
-@@ -0,0 +1,1108 @@
-+/***
-+ 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;
-+};
-+
-+struct device_mute_control {
-+ struct device *device;
-+ pa_mute_control *mute_control;
-+
-+ bool unlinked;
-+
-+ pa_hook_slot *mute_changed_slot;
-+};
-+
-+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 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 int volume_control_set_volume_cb(pa_volume_control *c, const pa_bvolume *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(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 = volume->volume;
-+
-+ if (set_balance)
-+ pa_bvolume_copy_balance(&bvolume, 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 struct device_volume_control *device_volume_control_new(struct device *device) {
-+ struct device_volume_control *control;
-+ const char *name = NULL;
-+ bool convertible_to_dB = false;
-+ bool channel_map_is_writable;
-+
-+ pa_assert(device);
-+
-+ 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)
-+ convertible_to_dB = device->sink->flags & PA_SINK_DECIBEL_VOLUME;
-+ else
-+ convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME;
-+
-+ break;
-+
-+ case DEVICE_TYPE_PORT_MONITOR:
-+ name = "port-monitor-volume-control";
-+ convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME;
-+ break;
-+
-+ case DEVICE_TYPE_SINK:
-+ name = "sink-volume-control";
-+ convertible_to_dB = device->sink->flags & PA_SINK_DECIBEL_VOLUME;
-+ break;
-+
-+ case DEVICE_TYPE_SOURCE:
-+ name = "source-volume-control";
-+ convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME;
-+ break;
-+ }
-+
-+ channel_map_is_writable = false;
-+ control->volume_control = pa_volume_control_new(device->creator->volume_api, name, device->device->description,
-+ convertible_to_dB, channel_map_is_writable);
-+ control->volume_control->set_volume = volume_control_set_volume_cb;
-+ control->volume_control->userdata = control;
-+
-+ return control;
-+}
-+
-+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
-+ pa_bvolume_from_cvolume(&bvolume, &source->reference_volume, &source->channel_map);
-+
-+ pa_volume_control_volume_changed(control->volume_control, &bvolume, true, true);
-+
-+ return PA_HOOK_OK;
-+}
-+
-+static void volume_control_set_initial_volume_cb(pa_volume_control *c) {
-+ struct device_volume_control *control;
-+ struct device *device;
-+ pa_cvolume cvolume;
-+
-+ pa_assert(c);
-+
-+ control = c->userdata;
-+ device = control->device;
-+ pa_bvolume_to_cvolume(&control->volume_control->volume, &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;
-+ }
-+}
-+
-+static void device_volume_control_put(struct device_volume_control *control) {
-+ struct device *device;
-+ pa_bvolume volume;
-+
-+ pa_assert(control);
-+
-+ device = control->device;
-+
-+ switch (device->type) {
-+ case DEVICE_TYPE_PORT:
-+ 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);
-+ } 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);
-+ }
-+ break;
-+
-+ case DEVICE_TYPE_PORT_MONITOR:
-+ case DEVICE_TYPE_SOURCE:
-+ 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);
-+ break;
-+
-+ case DEVICE_TYPE_SINK:
-+ 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);
-+ break;
-+ }
-+
-+ pa_volume_control_put(control->volume_control, &volume, volume_control_set_initial_volume_cb);
-+}
-+
-+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);
-+
-+ if (control->volume_changed_slot) {
-+ pa_hook_slot_free(control->volume_changed_slot);
-+ control->volume_changed_slot = NULL;
-+ }
-+}
-+
-+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);
-+
-+ pa_xfree(control);
-+}
-+
-+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 struct device_mute_control *device_mute_control_new(struct device *device) {
-+ struct device_mute_control *control;
-+ const char *name = NULL;
-+
-+ pa_assert(device);
-+
-+ control = pa_xnew0(struct device_mute_control, 1);
-+ control->device = device;
-+
-+ switch (device->type) {
-+ case DEVICE_TYPE_PORT:
-+ name = "port-mute-control";
-+ break;
-+
-+ case DEVICE_TYPE_PORT_MONITOR:
-+ name = "port-monitor-mute-control";
-+ break;
-+
-+ case DEVICE_TYPE_SINK:
-+ name = "sink-mute-control";
-+ break;
-+
-+ case DEVICE_TYPE_SOURCE:
-+ name = "source-mute-control";
-+ break;
-+ }
-+
-+ control->mute_control = pa_mute_control_new(device->creator->volume_api, name, device->device->description);
-+ control->mute_control->set_mute = mute_control_set_mute_cb;
-+ control->mute_control->userdata = control;
-+
-+ return 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
-+ mute = source->muted;
-+
-+ pa_mute_control_mute_changed(control->mute_control, mute);
-+
-+ return PA_HOOK_OK;
-+}
-+
-+static void mute_control_set_initial_mute_cb(pa_mute_control *c) {
-+ struct device_volume_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, c->mute, true);
-+ else
-+ pa_source_set_mute(device->source, c->mute, true);
-+ break;
-+
-+ case DEVICE_TYPE_PORT_MONITOR:
-+ case DEVICE_TYPE_SOURCE:
-+ pa_source_set_mute(device->source, c->mute, true);
-+ break;
-+
-+ case DEVICE_TYPE_SINK:
-+ pa_sink_set_mute(device->sink, c->mute, true);
-+ break;
-+ }
-+}
-+
-+static void device_mute_control_put(struct device_mute_control *control) {
-+ struct device *device;
-+ bool mute = false;
-+
-+ pa_assert(control);
-+
-+ device = control->device;
-+
-+ switch (device->type) {
-+ case DEVICE_TYPE_PORT:
-+ 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:
-+ case DEVICE_TYPE_SOURCE:
-+ 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;
-+
-+ case DEVICE_TYPE_SINK:
-+ 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;
-+ }
-+
-+ pa_mute_control_put(control->mute_control, mute, true, mute_control_set_initial_mute_cb);
-+}
-+
-+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);
-+
-+ if (control->mute_changed_slot) {
-+ pa_hook_slot_free(control->mute_changed_slot);
-+ control->mute_changed_slot = NULL;
-+ }
-+}
-+
-+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);
-+
-+ 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_description_changed(device->volume_control->volume_control, description);
-+ pa_mute_control_description_changed(device->mute_control->mute_control, description);
-+
-+ return PA_HOOK_OK;
-+}
-+
-+static struct device *device_new(pa_device_creator *creator, enum device_type type, void *core_device) {
-+ 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;
-+
-+ pa_assert(creator);
-+ pa_assert(core_device);
-+
-+ 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;
-+ }
-+
-+ device->device = pa_device_new(creator->volume_api, name, description, direction, &device_type, device_type ? 1 : 0);
-+ pa_xfree(description);
-+
-+ if (create_volume_and_mute_controls) {
-+ device->volume_control = device_volume_control_new(device);
-+ device->mute_control = device_mute_control_new(device);
-+ }
-+
-+ switch (type) {
-+ case DEVICE_TYPE_PORT:
-+ if (device->port->direction == PA_DIRECTION_OUTPUT)
-+ device->monitor = device_new(creator, DEVICE_TYPE_PORT_MONITOR, device->port);
-+ 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;
-+ }
-+
-+ return device;
-+}
-+
-+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 && !device->volume_control) {
-+ pa_assert(!device->mute_control);
-+
-+ device->volume_control = device_volume_control_new(device);
-+ device_volume_control_put(device->volume_control);
-+ pa_device_set_default_volume_control(device->device, device->volume_control->volume_control);
-+
-+ device->mute_control = device_mute_control_new(device);
-+ 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 && device->volume_control) {
-+ pa_assert(device->mute_control);
-+
-+ device_mute_control_free(device->mute_control);
-+ device->mute_control = NULL;
-+ 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;
-+
-+ 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;
-+ }
-+ }
-+
-+ device = device_new(creator, type, core_device);
-+ 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);
-+}
-diff --git a/src/modules/volume-api/device-creator.h b/src/modules/volume-api/device-creator.h
-new file mode 100644
-index 0000000..bcec8d9
---- /dev/null
-+++ b/src/modules/volume-api/device-creator.h
-@@ -0,0 +1,32 @@
-+#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
-diff --git a/src/modules/volume-api/device.c b/src/modules/volume-api/device.c
-new file mode 100644
-index 0000000..ea496ba
---- /dev/null
-+++ b/src/modules/volume-api/device.c
-@@ -0,0 +1,293 @@
-+/***
-+ 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>
-+
-+pa_device *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 *device;
-+ unsigned i;
-+
-+ pa_assert(api);
-+ pa_assert(name);
-+ pa_assert(description);
-+ pa_assert(device_types || n_device_types == 0);
-+
-+ device = pa_xnew0(pa_device, 1);
-+ device->volume_api = api;
-+ device->index = pa_volume_api_allocate_device_index(api);
-+ pa_assert_se(pa_volume_api_register_name(api, name, false, &device->name) >= 0);
-+ 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;
-+
-+ return device;
-+}
-+
-+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_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_UNLINK], device);
-+
-+ pa_volume_api_remove_device(device->volume_api, device);
-+
-+ if (device->mute_control) {
-+ pa_mute_control_remove_device(device->mute_control, device);
-+ device->mute_control = NULL;
-+ }
-+
-+ if (device->default_mute_control) {
-+ pa_mute_control_remove_default_for_device(device->default_mute_control, device);
-+ device->default_mute_control = NULL;
-+ }
-+
-+ if (device->volume_control) {
-+ pa_volume_control_remove_device(device->volume_control, device);
-+ device->volume_control = NULL;
-+ }
-+
-+ if (device->default_volume_control) {
-+ pa_volume_control_remove_default_for_device(device->default_volume_control, device);
-+ device->default_volume_control = NULL;
-+ }
-+}
-+
-+void pa_device_free(pa_device *device) {
-+ pa_assert(device);
-+
-+ if (!device->unlinked)
-+ 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);
-+}
-diff --git a/src/modules/volume-api/device.h b/src/modules/volume-api/device.h
-new file mode 100644
-index 0000000..9eac7e9
---- /dev/null
-+++ b/src/modules/volume-api/device.h
-@@ -0,0 +1,76 @@
-+#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;
-+};
-+
-+pa_device *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);
-+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
-diff --git a/src/modules/volume-api/mute-control.c b/src/modules/volume-api/mute-control.c
-new file mode 100644
-index 0000000..adc008e
---- /dev/null
-+++ b/src/modules/volume-api/mute-control.c
-@@ -0,0 +1,306 @@
-+/***
-+ 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>
-+
-+pa_mute_control *pa_mute_control_new(pa_volume_api *api, const char *name, const char *description) {
-+ pa_mute_control *control;
-+
-+ pa_assert(api);
-+ pa_assert(name);
-+ pa_assert(description);
-+
-+ control = pa_xnew0(pa_mute_control, 1);
-+ control->volume_api = api;
-+ control->index = pa_volume_api_allocate_mute_control_index(api);
-+ pa_assert_se(pa_volume_api_register_name(api, name, false, &control->name) >= 0);
-+ control->description = pa_xstrdup(description);
-+ control->proplist = pa_proplist_new();
-+ control->devices = pa_hashmap_new(NULL, NULL);
-+ control->default_for_devices = pa_hashmap_new(NULL, NULL);
-+ control->streams = pa_hashmap_new(NULL, NULL);
-+ control->audio_groups = pa_hashmap_new(NULL, NULL);
-+
-+ return control;
-+}
-+
-+void pa_mute_control_put(pa_mute_control *control, bool initial_mute, bool initial_mute_is_set,
-+ pa_mute_control_set_initial_mute_cb_t set_initial_mute_cb) {
-+ const char *prop_key;
-+ void *state = NULL;
-+
-+ pa_assert(control);
-+ pa_assert(initial_mute_is_set || control->set_mute);
-+ pa_assert(set_initial_mute_cb || !control->set_mute);
-+
-+ if (initial_mute_is_set)
-+ control->mute = initial_mute;
-+ else
-+ control->mute = false;
-+
-+ if (set_initial_mute_cb)
-+ set_initial_mute_cb(control);
-+
-+ 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(" 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_audio_group *group;
-+ pa_device *device;
-+ pas_stream *stream;
-+
-+ 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_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK], control);
-+
-+ pa_volume_api_remove_mute_control(control->volume_api, control);
-+
-+ while ((group = pa_hashmap_first(control->audio_groups)))
-+ pa_audio_group_set_mute_control(group, NULL);
-+
-+ while ((stream = pa_hashmap_first(control->streams)))
-+ pas_stream_set_mute_control(stream, NULL);
-+
-+ 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);
-+
-+ if (!control->unlinked)
-+ pa_mute_control_unlink(control);
-+
-+ if (control->audio_groups) {
-+ pa_assert(pa_hashmap_isempty(control->audio_groups));
-+ pa_hashmap_free(control->audio_groups);
-+ }
-+
-+ if (control->streams) {
-+ pa_assert(pa_hashmap_isempty(control->streams));
-+ pa_hashmap_free(control->streams);
-+ }
-+
-+ 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_owner_audio_group(pa_mute_control *control, pa_audio_group *group) {
-+ pa_assert(control);
-+ pa_assert(group);
-+
-+ control->owner_audio_group = group;
-+}
-+
-+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->linked || control->unlinked)
-+ return;
-+
-+ pa_log_debug("The mute of mute control %s changed from %s to %s.", control->name, pa_yes_no(old_mute),
-+ pa_yes_no(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) {
-+ pa_log_info("Tried to set the mute of mute control %s, but the mute control doesn't support the operation.",
-+ control->name);
-+ return -PA_ERR_NOTSUPPORTED;
-+ }
-+
-+ if (mute == control->mute)
-+ return 0;
-+
-+ control->set_mute_in_progress = true;
-+ r = control->set_mute(control, mute);
-+ control->set_mute_in_progress = false;
-+
-+ if (r >= 0)
-+ set_mute_internal(control, mute);
-+
-+ return r;
-+}
-+
-+void pa_mute_control_description_changed(pa_mute_control *control, const char *new_description) {
-+ char *old_description;
-+
-+ pa_assert(control);
-+ pa_assert(new_description);
-+
-+ old_description = control->description;
-+
-+ if (pa_streq(new_description, old_description))
-+ return;
-+
-+ control->description = pa_xstrdup(new_description);
-+ pa_log_debug("The description of mute control %s changed from \"%s\" to \"%s\".", control->name, old_description,
-+ new_description);
-+ pa_xfree(old_description);
-+ pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_DESCRIPTION_CHANGED], control);
-+}
-+
-+void pa_mute_control_mute_changed(pa_mute_control *control, bool new_mute) {
-+ pa_assert(control);
-+
-+ if (!control->linked)
-+ return;
-+
-+ if (control->set_mute_in_progress)
-+ return;
-+
-+ set_mute_internal(control, new_mute);
-+}
-+
-+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));
-+}
-+
-+void pa_mute_control_add_stream(pa_mute_control *control, pas_stream *stream) {
-+ pa_assert(control);
-+ pa_assert(stream);
-+
-+ pa_assert_se(pa_hashmap_put(control->streams, stream, stream) >= 0);
-+}
-+
-+void pa_mute_control_remove_stream(pa_mute_control *control, pas_stream *stream) {
-+ pa_assert(control);
-+ pa_assert(stream);
-+
-+ pa_assert_se(pa_hashmap_remove(control->streams, stream));
-+}
-+
-+void pa_mute_control_add_audio_group(pa_mute_control *control, pa_audio_group *group) {
-+ pa_assert(control);
-+ pa_assert(group);
-+
-+ pa_assert_se(pa_hashmap_put(control->audio_groups, group, group) >= 0);
-+}
-+
-+void pa_mute_control_remove_audio_group(pa_mute_control *control, pa_audio_group *group) {
-+ pa_assert(control);
-+ pa_assert(group);
-+
-+ pa_assert_se(pa_hashmap_remove(control->audio_groups, group));
-+}
-diff --git a/src/modules/volume-api/mute-control.h b/src/modules/volume-api/mute-control.h
-new file mode 100644
-index 0000000..1f70a43
---- /dev/null
-+++ b/src/modules/volume-api/mute-control.h
-@@ -0,0 +1,102 @@
-+#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/volume-api.h>
-+
-+typedef struct pa_mute_control pa_mute_control;
-+
-+struct pa_mute_control {
-+ pa_volume_api *volume_api;
-+ uint32_t index;
-+ const char *name;
-+ char *description;
-+ pa_proplist *proplist;
-+ bool mute;
-+
-+ /* 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) */
-+ pa_hashmap *streams; /* pas_stream -> pas_stream (hashmap-as-a-set) */
-+ pa_hashmap *audio_groups; /* pa_audio_group -> pa_audio_group (hashmap-as-a-set) */
-+
-+ 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. May be NULL, if the mute
-+ * control is read-only. */
-+ int (*set_mute)(pa_mute_control *control, bool mute);
-+
-+ void *userdata;
-+};
-+
-+pa_mute_control *pa_mute_control_new(pa_volume_api *api, const char *name, const char *description);
-+
-+typedef void (*pa_mute_control_set_initial_mute_cb_t)(pa_mute_control *control);
-+
-+/* initial_mute is the preferred initial mute of the mute control
-+ * implementation. It may be unset, if the implementation doesn't care about
-+ * the initial state of the mute control. Read-only mute controls, however,
-+ * must always set initial_mute.
-+ *
-+ * The implementation's initial mute preference may be overridden by policy, if
-+ * the mute control isn't read-only. When the final initial mute is known, the
-+ * the implementation is notified via set_initial_mute_cb (the mute can be read
-+ * from control->mute). set_initial_mute_cb may be NULL, if the mute control is
-+ * read-only. */
-+void pa_mute_control_put(pa_mute_control *control, bool initial_mute, bool initial_mute_is_set,
-+ pa_mute_control_set_initial_mute_cb_t set_initial_mute_cb);
-+
-+void pa_mute_control_unlink(pa_mute_control *control);
-+void pa_mute_control_free(pa_mute_control *control);
-+
-+/* Called by audio-group.c only. */
-+void pa_mute_control_set_owner_audio_group(pa_mute_control *control, pa_audio_group *group);
-+
-+/* Called by clients and policy modules. */
-+int pa_mute_control_set_mute(pa_mute_control *control, bool mute);
-+
-+/* Called by the mute control implementation. */
-+void pa_mute_control_description_changed(pa_mute_control *control, const char *new_description);
-+void pa_mute_control_mute_changed(pa_mute_control *control, bool new_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);
-+
-+/* Called from sstream.c only. */
-+void pa_mute_control_add_stream(pa_mute_control *control, pas_stream *stream);
-+void pa_mute_control_remove_stream(pa_mute_control *control, pas_stream *stream);
-+
-+/* Called from audio-group.c only. */
-+void pa_mute_control_add_audio_group(pa_mute_control *control, pa_audio_group *group);
-+void pa_mute_control_remove_audio_group(pa_mute_control *control, pa_audio_group *group);
-+
-+#endif
-diff --git a/src/modules/volume-api/sstream.c b/src/modules/volume-api/sstream.c
-new file mode 100644
-index 0000000..e3531a8
---- /dev/null
-+++ b/src/modules/volume-api/sstream.c
-@@ -0,0 +1,366 @@
-+/***
-+ 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/binding.h>
-+#include <modules/volume-api/mute-control.h>
-+#include <modules/volume-api/volume-control.h>
-+
-+#include <pulse/direction.h>
-+
-+#include <pulsecore/core-util.h>
-+
-+pas_stream *pas_stream_new(pa_volume_api *api, const char *name, const char *description, pa_direction_t direction) {
-+ pas_stream *stream;
-+
-+ pa_assert(api);
-+ pa_assert(name);
-+ pa_assert(description);
-+
-+ stream = pa_xnew0(pas_stream, 1);
-+ stream->volume_api = api;
-+ stream->index = pa_volume_api_allocate_stream_index(api);
-+ pa_assert_se(pa_volume_api_register_name(api, name, false, &stream->name) >= 0);
-+ stream->description = pa_xstrdup(description);
-+ stream->direction = direction;
-+ stream->proplist = pa_proplist_new();
-+ stream->use_default_volume_control = true;
-+ stream->use_default_mute_control = true;
-+
-+ return stream;
-+}
-+
-+static void set_volume_control_internal(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;
-+
-+ if (old_control) {
-+ /* If the old control pointed to the own volume control of an audio
-+ * group, then the stream's audio group for volume needs to be
-+ * updated. We set it to NULL here, and if it should be non-NULL, that
-+ * will be fixed very soon (a few lines down). */
-+ pas_stream_set_audio_group_for_volume(stream, NULL);
-+
-+ pa_volume_control_remove_stream(old_control, stream);
-+ }
-+
-+ stream->volume_control = control;
-+
-+ if (control) {
-+ pa_volume_control_add_stream(control, stream);
-+ pas_stream_set_audio_group_for_volume(stream, control->owner_audio_group);
-+ }
-+
-+ 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);
-+}
-+
-+static void set_mute_control_internal(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;
-+
-+ if (old_control) {
-+ /* If the old control pointed to the own mute control of an audio
-+ * group, then the stream's audio group for mute needs to be updated.
-+ * We set it to NULL here, and if it should be non-NULL, that will be
-+ * fixed very soon (a few lines down). */
-+ pas_stream_set_audio_group_for_mute(stream, NULL);
-+
-+ pa_mute_control_remove_stream(old_control, stream);
-+ }
-+
-+ stream->mute_control = control;
-+
-+ if (control) {
-+ pa_mute_control_add_stream(control, stream);
-+ pas_stream_set_audio_group_for_mute(stream, control->owner_audio_group);
-+ }
-+
-+ 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_put(pas_stream *stream, pa_proplist *initial_properties) {
-+ const char *prop_key;
-+ void *state = NULL;
-+
-+ pa_assert(stream);
-+ pa_assert(!stream->create_own_volume_control || stream->delete_own_volume_control);
-+ pa_assert(!stream->create_own_mute_control || stream->delete_own_mute_control);
-+
-+ if (initial_properties)
-+ pa_proplist_update(stream->proplist, PA_UPDATE_REPLACE, initial_properties);
-+
-+ pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_VOLUME_CONTROL], stream);
-+
-+ if (stream->use_default_volume_control)
-+ set_volume_control_internal(stream, stream->own_volume_control);
-+
-+ pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_MUTE_CONTROL], stream);
-+
-+ if (stream->use_default_mute_control)
-+ set_mute_control_internal(stream, stream->own_mute_control);
-+
-+ 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(" 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_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_UNLINK], stream);
-+
-+ pa_volume_api_remove_stream(stream->volume_api, 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_volume_control(stream, NULL);
-+ pas_stream_set_have_own_mute_control(stream, false);
-+ pas_stream_set_have_own_volume_control(stream, false);
-+}
-+
-+void pas_stream_free(pas_stream *stream) {
-+ pa_assert(stream);
-+
-+ if (!stream->unlinked)
-+ 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);
-+}
-+
-+int pas_stream_set_have_own_volume_control(pas_stream *stream, bool have) {
-+ pa_assert(stream);
-+
-+ if (have == stream->have_own_volume_control)
-+ return 0;
-+
-+ if (have) {
-+ pa_assert(!stream->own_volume_control);
-+
-+ if (!stream->create_own_volume_control) {
-+ pa_log_debug("Stream %s doesn't support own volume control.", stream->name);
-+ return -PA_ERR_NOTSUPPORTED;
-+ }
-+
-+ stream->own_volume_control = stream->create_own_volume_control(stream);
-+ } else {
-+ stream->delete_own_volume_control(stream);
-+ stream->own_volume_control = NULL;
-+ }
-+
-+ stream->have_own_volume_control = have;
-+
-+ return 0;
-+}
-+
-+int pas_stream_set_have_own_mute_control(pas_stream *stream, bool have) {
-+ pa_assert(stream);
-+
-+ if (have == stream->have_own_mute_control)
-+ return 0;
-+
-+ if (have) {
-+ pa_assert(!stream->own_mute_control);
-+
-+ if (!stream->create_own_mute_control) {
-+ pa_log_debug("Stream %s doesn't support own mute control.", stream->name);
-+ return -PA_ERR_NOTSUPPORTED;
-+ }
-+
-+ stream->own_mute_control = stream->create_own_mute_control(stream);
-+ } else {
-+ stream->delete_own_mute_control(stream);
-+ stream->own_mute_control = NULL;
-+ }
-+
-+ stream->have_own_mute_control = have;
-+
-+ return 0;
-+}
-+
-+void pas_stream_set_volume_control(pas_stream *stream, pa_volume_control *control) {
-+ pa_assert(stream);
-+
-+ stream->use_default_volume_control = false;
-+
-+ if (stream->volume_control_binding) {
-+ pa_binding_free(stream->volume_control_binding);
-+ stream->volume_control_binding = NULL;
-+ }
-+
-+ set_volume_control_internal(stream, control);
-+}
-+
-+void pas_stream_set_mute_control(pas_stream *stream, pa_mute_control *control) {
-+ pa_assert(stream);
-+
-+ stream->use_default_mute_control = false;
-+
-+ if (stream->mute_control_binding) {
-+ pa_binding_free(stream->mute_control_binding);
-+ stream->mute_control_binding = NULL;
-+ }
-+
-+ set_mute_control_internal(stream, control);
-+}
-+
-+void pas_stream_bind_volume_control(pas_stream *stream, pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = stream,
-+ .set_value = (pa_binding_set_value_cb_t) set_volume_control_internal,
-+ };
-+
-+ pa_assert(stream);
-+ pa_assert(target_info);
-+
-+ stream->use_default_volume_control = false;
-+
-+ if (stream->volume_control_binding)
-+ pa_binding_free(stream->volume_control_binding);
-+
-+ stream->volume_control_binding = pa_binding_new(stream->volume_api, &owner_info, target_info);
-+}
-+
-+void pas_stream_bind_mute_control(pas_stream *stream, pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = stream,
-+ .set_value = (pa_binding_set_value_cb_t) set_mute_control_internal,
-+ };
-+
-+ pa_assert(stream);
-+ pa_assert(target_info);
-+
-+ stream->use_default_mute_control = false;
-+
-+ if (stream->mute_control_binding)
-+ pa_binding_free(stream->mute_control_binding);
-+
-+ stream->mute_control_binding = pa_binding_new(stream->volume_api, &owner_info, target_info);
-+}
-+
-+void pas_stream_description_changed(pas_stream *stream, const char *new_description) {
-+ char *old_description;
-+
-+ pa_assert(stream);
-+ pa_assert(new_description);
-+
-+ old_description = stream->description;
-+
-+ if (pa_streq(new_description, old_description))
-+ return;
-+
-+ stream->description = pa_xstrdup(new_description);
-+ pa_log_debug("The description of stream %s changed from \"%s\" to \"%s\".", stream->name, old_description,
-+ new_description);
-+ pa_xfree(old_description);
-+ pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_DESCRIPTION_CHANGED], stream);
-+}
-+
-+void pas_stream_set_audio_group_for_volume(pas_stream *stream, pa_audio_group *group) {
-+ pa_assert(stream);
-+
-+ if (group == stream->audio_group_for_volume)
-+ return;
-+
-+ if (stream->audio_group_for_volume)
-+ pa_audio_group_remove_volume_stream(stream->audio_group_for_volume, stream);
-+
-+ stream->audio_group_for_volume = group;
-+
-+ if (group)
-+ pa_audio_group_add_volume_stream(group, stream);
-+}
-+
-+void pas_stream_set_audio_group_for_mute(pas_stream *stream, pa_audio_group *group) {
-+ pa_assert(stream);
-+
-+ if (group == stream->audio_group_for_mute)
-+ return;
-+
-+ if (stream->audio_group_for_mute)
-+ pa_audio_group_remove_mute_stream(stream->audio_group_for_mute, stream);
-+
-+ stream->audio_group_for_mute = group;
-+
-+ if (group)
-+ pa_audio_group_add_mute_stream(group, stream);
-+}
-diff --git a/src/modules/volume-api/sstream.h b/src/modules/volume-api/sstream.h
-new file mode 100644
-index 0000000..a65b34c
---- /dev/null
-+++ b/src/modules/volume-api/sstream.h
-@@ -0,0 +1,108 @@
-+#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_mute_control *mute_control;
-+ bool use_default_volume_control;
-+ bool use_default_mute_control;
-+ bool have_own_volume_control;
-+ bool have_own_mute_control;
-+ pa_volume_control *own_volume_control;
-+ pa_mute_control *own_mute_control;
-+
-+ pa_binding *volume_control_binding;
-+ pa_binding *mute_control_binding;
-+ pa_audio_group *audio_group_for_volume;
-+ pa_audio_group *audio_group_for_mute;
-+
-+ bool linked;
-+ bool unlinked;
-+
-+ /* Called when the own volume control is enabled. The callback
-+ * implementation should return a new linked volume control object. The
-+ * callback may be NULL, in which case the own volume control can't be
-+ * enabled. */
-+ pa_volume_control *(*create_own_volume_control)(pas_stream *stream);
-+
-+ /* Called when the own volume control is disabled. The implementation
-+ * should free stream->own_volume_control. The callback may be NULL only if
-+ * create_own_volume_control is NULL also. */
-+ void (*delete_own_volume_control)(pas_stream *stream);
-+
-+ /* Called when the own mute control is enabled. The callback implementation
-+ * should return a new linked mute control object. The callback may be
-+ * NULL, in which case the own mute control can't be enabled. */
-+ pa_mute_control *(*create_own_mute_control)(pas_stream *stream);
-+
-+ /* Called when the own mute control is disabled. The implementation should
-+ * free stream->own_mute_control. The callback may be NULL only if
-+ * create_own_mute_control is NULL also. */
-+ void (*delete_own_mute_control)(pas_stream *stream);
-+
-+ void *userdata;
-+};
-+
-+pas_stream *pas_stream_new(pa_volume_api *api, const char *name, const char *description, pa_direction_t direction);
-+void pas_stream_put(pas_stream *stream, pa_proplist *initial_properties);
-+void pas_stream_unlink(pas_stream *stream);
-+void pas_stream_free(pas_stream *stream);
-+
-+/* Called by the stream implementation and possibly by policy modules.
-+ * Enabling own controls may fail (the stream may not support own controls),
-+ * disabling will never fail. */
-+int pas_stream_set_have_own_volume_control(pas_stream *stream, bool have);
-+int pas_stream_set_have_own_mute_control(pas_stream *stream, bool have);
-+
-+/* Called by policy modules. */
-+void pas_stream_set_volume_control(pas_stream *stream, pa_volume_control *control);
-+void pas_stream_set_mute_control(pas_stream *stream, pa_mute_control *control);
-+void pas_stream_bind_volume_control(pas_stream *stream, pa_binding_target_info *target_info);
-+void pas_stream_bind_mute_control(pas_stream *stream, pa_binding_target_info *target_info);
-+
-+/* Called by the stream implementation. */
-+void pas_stream_description_changed(pas_stream *stream, const char *new_description);
-+
-+/* Called by audio-group.c only. Adding a stream to an audio group happens
-+ * implicitly when the volume or mute control of a stream is set to point to
-+ * the own control of an audio group. */
-+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
-diff --git a/src/modules/volume-api/stream-creator.c b/src/modules/volume-api/stream-creator.c
-new file mode 100644
-index 0000000..2bd0053
---- /dev/null
-+++ b/src/modules/volume-api/stream-creator.c
-@@ -0,0 +1,691 @@
-+/***
-+ 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_put_slot;
-+ pa_hook_slot *sink_input_unlink_slot;
-+ pa_hook_slot *source_output_put_slot;
-+ pa_hook_slot *source_output_unlink_slot;
-+};
-+
-+enum stream_type {
-+ STREAM_TYPE_SINK_INPUT,
-+ STREAM_TYPE_SOURCE_OUTPUT,
-+};
-+
-+struct stream {
-+ pa_stream_creator *creator;
-+ enum stream_type type;
-+ pa_sink_input *sink_input;
-+ pa_source_output *source_output;
-+ pa_client *client;
-+ pas_stream *stream;
-+
-+ bool unlinked;
-+
-+ pa_hook_slot *proplist_changed_slot;
-+ pa_hook_slot *client_proplist_changed_slot;
-+ pa_hook_slot *volume_changed_slot;
-+ pa_hook_slot *mute_changed_slot;
-+};
-+
-+static char *get_stream_volume_and_mute_control_description_malloc(struct stream *stream) {
-+ const char *application_name = NULL;
-+ char *description;
-+
-+ pa_assert(stream);
-+
-+ if (stream->client)
-+ application_name = pa_proplist_gets(stream->client->proplist, PA_PROP_APPLICATION_NAME);
-+
-+ if (application_name)
-+ description = pa_sprintf_malloc("%s: %s", application_name, stream->stream->description);
-+ else
-+ description = pa_xstrdup(stream->stream->description);
-+
-+ return description;
-+}
-+
-+static int volume_control_set_volume_cb(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance) {
-+ struct stream *stream;
-+ pa_bvolume bvolume;
-+ pa_cvolume cvolume;
-+
-+ pa_assert(control);
-+ pa_assert(volume);
-+
-+ stream = control->userdata;
-+
-+ switch (stream->type) {
-+ case STREAM_TYPE_SINK_INPUT:
-+ pa_bvolume_from_cvolume(&bvolume, &stream->sink_input->volume, &stream->sink_input->channel_map);
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ pa_bvolume_from_cvolume(&bvolume, &stream->source_output->volume, &stream->source_output->channel_map);
-+ break;
-+ }
-+
-+ if (set_volume)
-+ bvolume.volume = volume->volume;
-+
-+ if (set_balance)
-+ pa_bvolume_copy_balance(&bvolume, volume);
-+
-+ pa_bvolume_to_cvolume(&bvolume, &cvolume);
-+
-+ switch (stream->type) {
-+ case STREAM_TYPE_SINK_INPUT:
-+ pa_sink_input_set_volume(stream->sink_input, &cvolume, true, true);
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ 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);
-+
-+ 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
-+ pa_bvolume_from_cvolume(&bvolume, &output->volume, &output->channel_map);
-+
-+ pa_volume_control_volume_changed(stream->stream->own_volume_control, &bvolume, true, true);
-+
-+ return PA_HOOK_OK;
-+}
-+
-+static void volume_control_set_initial_volume_cb(pa_volume_control *control) {
-+ struct stream *stream;
-+ pa_cvolume cvolume;
-+
-+ pa_assert(control);
-+
-+ stream = control->userdata;
-+ pa_bvolume_to_cvolume(&control->volume, &cvolume);
-+
-+ switch (stream->type) {
-+ case STREAM_TYPE_SINK_INPUT:
-+ pa_sink_input_set_volume(stream->sink_input, &cvolume, true, true);
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ pa_source_output_set_volume(stream->source_output, &cvolume, true, true);
-+ break;
-+ }
-+}
-+
-+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:
-+ pa_sink_input_set_mute(stream->sink_input, mute, true);
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ 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);
-+
-+ 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
-+ mute = output->muted;
-+
-+ pa_mute_control_mute_changed(stream->stream->own_mute_control, mute);
-+
-+ return PA_HOOK_OK;
-+}
-+
-+static void mute_control_set_initial_mute_cb(pa_mute_control *control) {
-+ struct stream *stream;
-+
-+ pa_assert(control);
-+
-+ stream = control->userdata;
-+
-+ switch (stream->type) {
-+ case STREAM_TYPE_SINK_INPUT:
-+ pa_sink_input_set_mute(stream->sink_input, control->mute, true);
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ pa_source_output_set_mute(stream->source_output, control->mute, true);
-+ break;
-+ }
-+}
-+
-+static const char *get_sink_input_description(pa_sink_input *input) {
-+ const char *description;
-+
-+ pa_assert(input);
-+
-+ description = pa_proplist_gets(input->proplist, PA_PROP_MEDIA_NAME);
-+ if (description)
-+ return description;
-+
-+ return NULL;
-+}
-+
-+static const char *get_source_output_description(pa_source_output *output) {
-+ const char *description;
-+
-+ pa_assert(output);
-+
-+ description = pa_proplist_gets(output->proplist, PA_PROP_MEDIA_NAME);
-+ if (description)
-+ return description;
-+
-+ return NULL;
-+}
-+
-+static pa_volume_control *stream_create_own_volume_control_cb(pas_stream *s) {
-+ struct stream *stream;
-+ const char *name = NULL;
-+ char *description;
-+ pa_volume_control *control;
-+ pa_bvolume volume;
-+
-+ pa_assert(s);
-+
-+ stream = s->userdata;
-+
-+ switch (stream->type) {
-+ case STREAM_TYPE_SINK_INPUT:
-+ name = "sink-input-volume-control";
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ name = "source-output-volume-control";
-+ break;
-+ }
-+
-+ description = get_stream_volume_and_mute_control_description_malloc(stream);
-+ control = pa_volume_control_new(stream->creator->volume_api, name, description, true, false);
-+ pa_xfree(description);
-+ control->set_volume = volume_control_set_volume_cb;
-+ control->userdata = stream;
-+
-+ pa_assert(!stream->volume_changed_slot);
-+
-+ switch (stream->type) {
-+ case STREAM_TYPE_SINK_INPUT:
-+ stream->volume_changed_slot =
-+ pa_hook_connect(&stream->sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED], PA_HOOK_NORMAL,
-+ sink_input_or_source_output_volume_changed_cb, stream);
-+ pa_bvolume_from_cvolume(&volume, &stream->sink_input->volume, &stream->sink_input->channel_map);
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ stream->volume_changed_slot =
-+ pa_hook_connect(&stream->source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED],
-+ PA_HOOK_NORMAL, sink_input_or_source_output_volume_changed_cb, stream);
-+ pa_bvolume_from_cvolume(&volume, &stream->source_output->volume, &stream->source_output->channel_map);
-+ break;
-+ }
-+
-+ pa_volume_control_put(control, &volume, volume_control_set_initial_volume_cb);
-+
-+ return control;
-+}
-+
-+static void stream_delete_own_volume_control_cb(pas_stream *s) {
-+ struct stream *stream;
-+
-+ pa_assert(s);
-+
-+ stream = s->userdata;
-+ pa_hook_slot_free(stream->volume_changed_slot);
-+ stream->volume_changed_slot = NULL;
-+ pa_volume_control_free(s->own_volume_control);
-+}
-+
-+static pa_mute_control *stream_create_own_mute_control_cb(pas_stream *s) {
-+ struct stream *stream;
-+ const char *name = NULL;
-+ char *description;
-+ pa_mute_control *control;
-+ bool mute = false;
-+
-+ pa_assert(s);
-+
-+ stream = s->userdata;
-+
-+ switch (stream->type) {
-+ case STREAM_TYPE_SINK_INPUT:
-+ name = "sink-input-mute-control";
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ name = "source-output-mute-control";
-+ break;
-+ }
-+
-+ description = get_stream_volume_and_mute_control_description_malloc(stream);
-+ control = pa_mute_control_new(stream->creator->volume_api, name, description);
-+ pa_xfree(description);
-+ control->set_mute = mute_control_set_mute_cb;
-+ control->userdata = stream;
-+
-+ pa_assert(!stream->mute_changed_slot);
-+
-+ switch (stream->type) {
-+ case STREAM_TYPE_SINK_INPUT:
-+ stream->mute_changed_slot =
-+ pa_hook_connect(&stream->sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED], PA_HOOK_NORMAL,
-+ sink_input_or_source_output_mute_changed_cb, stream);
-+ mute = stream->sink_input->muted;
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ stream->mute_changed_slot =
-+ pa_hook_connect(&stream->source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED],
-+ PA_HOOK_NORMAL, sink_input_or_source_output_mute_changed_cb, stream);
-+ mute = stream->source_output->muted;
-+ break;
-+ }
-+
-+ pa_mute_control_put(control, mute, true, mute_control_set_initial_mute_cb);
-+
-+ return control;
-+}
-+
-+static void stream_delete_own_mute_control_cb(pas_stream *s) {
-+ struct stream *stream;
-+
-+ pa_assert(s);
-+
-+ stream = s->userdata;
-+ pa_hook_slot_free(stream->mute_changed_slot);
-+ stream->mute_changed_slot = NULL;
-+ pa_mute_control_free(s->own_mute_control);
-+}
-+
-+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;
-+ const char *new_stream_description = NULL;
-+ char *new_control_description;
-+
-+ 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;
-+
-+ new_stream_description = get_sink_input_description(input);
-+ if (!new_stream_description)
-+ new_stream_description = stream->stream->name;
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ output = call_data;
-+
-+ if (output != stream->source_output)
-+ return PA_HOOK_OK;
-+
-+ new_stream_description = get_source_output_description(output);
-+ if (!new_stream_description)
-+ new_stream_description = stream->stream->name;
-+ break;
-+ }
-+
-+ pas_stream_description_changed(stream->stream, new_stream_description);
-+
-+ new_control_description = get_stream_volume_and_mute_control_description_malloc(stream);
-+
-+ if (stream->stream->own_volume_control)
-+ pa_volume_control_description_changed(stream->stream->own_volume_control, new_control_description);
-+
-+ if (stream->stream->own_mute_control)
-+ pa_mute_control_description_changed(stream->stream->own_mute_control, new_control_description);
-+
-+ pa_xfree(new_control_description);
-+
-+ return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t client_proplist_changed_cb(void *hook_data, void *call_data, void *userdata) {
-+ struct stream *stream = userdata;
-+ pa_client *client = call_data;
-+ char *description;
-+
-+ pa_assert(stream);
-+ pa_assert(client);
-+
-+ if (client != stream->client)
-+ return PA_HOOK_OK;
-+
-+ description = get_stream_volume_and_mute_control_description_malloc(stream);
-+
-+ if (stream->stream->own_volume_control)
-+ pa_volume_control_description_changed(stream->stream->own_volume_control, description);
-+
-+ if (stream->stream->own_mute_control)
-+ pa_mute_control_description_changed(stream->stream->own_mute_control, description);
-+
-+ pa_xfree(description);
-+
-+ return PA_HOOK_OK;
-+}
-+
-+static struct stream *stream_new(pa_stream_creator *creator, enum stream_type type, void *core_stream) {
-+ struct stream *stream;
-+ const char *name = NULL;
-+ const char *description = NULL;
-+ pa_direction_t direction = PA_DIRECTION_OUTPUT;
-+
-+ pa_assert(creator);
-+ pa_assert(core_stream);
-+
-+ stream = pa_xnew0(struct stream, 1);
-+ stream->creator = creator;
-+ stream->type = type;
-+
-+ switch (type) {
-+ case STREAM_TYPE_SINK_INPUT:
-+ stream->sink_input = core_stream;
-+ stream->client = stream->sink_input->client;
-+ name = "sink-input-stream";
-+
-+ description = get_sink_input_description(stream->sink_input);
-+ if (!description)
-+ description = name;
-+
-+ direction = PA_DIRECTION_OUTPUT;
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ stream->source_output = core_stream;
-+ stream->client = stream->source_output->client;
-+ name = "source-output-stream";
-+
-+ description = get_source_output_description(stream->source_output);
-+ if (!description)
-+ description = name;
-+
-+ direction = PA_DIRECTION_INPUT;
-+ break;
-+ }
-+
-+ stream->stream = pas_stream_new(creator->volume_api, name, description, direction);
-+ stream->stream->create_own_volume_control = stream_create_own_volume_control_cb;
-+ stream->stream->delete_own_volume_control = stream_delete_own_volume_control_cb;
-+ stream->stream->create_own_mute_control = stream_create_own_mute_control_cb;
-+ stream->stream->delete_own_mute_control = stream_delete_own_mute_control_cb;
-+ stream->stream->userdata = stream;
-+ pas_stream_set_have_own_volume_control(stream->stream, true);
-+ pas_stream_set_have_own_mute_control(stream->stream, true);
-+
-+ switch (type) {
-+ case STREAM_TYPE_SINK_INPUT:
-+ stream->proplist_changed_slot =
-+ pa_hook_connect(&stream->sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], PA_HOOK_NORMAL,
-+ sink_input_or_source_output_proplist_changed_cb, stream);
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ stream->proplist_changed_slot =
-+ pa_hook_connect(&stream->source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED],
-+ PA_HOOK_NORMAL, sink_input_or_source_output_proplist_changed_cb, stream);
-+ break;
-+ }
-+
-+ stream->client_proplist_changed_slot =
-+ pa_hook_connect(&stream->creator->volume_api->core->hooks[PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED],
-+ PA_HOOK_NORMAL, client_proplist_changed_cb, stream);
-+
-+ return stream;
-+}
-+
-+static void stream_put(struct stream *stream) {
-+ pa_proplist *proplist = NULL;
-+
-+ pa_assert(stream);
-+
-+ switch (stream->type) {
-+ case STREAM_TYPE_SINK_INPUT:
-+ proplist = stream->sink_input->proplist;
-+ break;
-+
-+ case STREAM_TYPE_SOURCE_OUTPUT:
-+ proplist = stream->source_output->proplist;
-+ break;
-+ }
-+
-+ pas_stream_put(stream->stream, proplist);
-+}
-+
-+static void stream_unlink(struct stream *stream) {
-+ pa_assert(stream);
-+
-+ if (stream->unlinked)
-+ return;
-+
-+ stream->unlinked = true;
-+
-+ if (stream->stream)
-+ pas_stream_unlink(stream->stream);
-+}
-+
-+static void stream_free(struct stream *stream) {
-+ pa_assert(stream);
-+
-+ if (!stream->unlinked)
-+ stream_unlink(stream);
-+
-+ if (stream->client_proplist_changed_slot)
-+ pa_hook_slot_free(stream->client_proplist_changed_slot);
-+
-+ if (stream->proplist_changed_slot)
-+ pa_hook_slot_free(stream->proplist_changed_slot);
-+
-+ if (stream->stream)
-+ pas_stream_free(stream->stream);
-+
-+ pa_xfree(stream);
-+}
-+
-+static void create_stream(pa_stream_creator *creator, enum stream_type type, void *core_stream) {
-+ struct stream *stream;
-+
-+ pa_assert(creator);
-+ pa_assert(core_stream);
-+
-+ stream = stream_new(creator, type, core_stream);
-+ pa_hashmap_put(creator->streams, core_stream, stream);
-+ stream_put(stream);
-+}
-+
-+static pa_hook_result_t sink_input_put_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);
-+
-+ create_stream(creator, STREAM_TYPE_SINK_INPUT, input);
-+
-+ 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_put_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);
-+
-+ create_stream(creator, STREAM_TYPE_SOURCE_OUTPUT, output);
-+
-+ 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;
-+
-+ 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_put_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_NORMAL,
-+ sink_input_put_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_put_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_NORMAL,
-+ source_output_put_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)
-+ create_stream(creator, STREAM_TYPE_SINK_INPUT, input);
-+
-+ PA_IDXSET_FOREACH(output, api->core->source_outputs, idx)
-+ create_stream(creator, STREAM_TYPE_SOURCE_OUTPUT, output);
-+
-+ 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_put_slot)
-+ pa_hook_slot_free(creator->source_output_put_slot);
-+
-+ if (creator->sink_input_unlink_slot)
-+ pa_hook_slot_free(creator->sink_input_unlink_slot);
-+
-+ if (creator->sink_input_put_slot)
-+ pa_hook_slot_free(creator->sink_input_put_slot);
-+
-+ if (creator->streams)
-+ pa_hashmap_free(creator->streams);
-+
-+ pa_xfree(creator);
-+}
-diff --git a/src/modules/volume-api/stream-creator.h b/src/modules/volume-api/stream-creator.h
-new file mode 100644
-index 0000000..97a03a4
---- /dev/null
-+++ b/src/modules/volume-api/stream-creator.h
-@@ -0,0 +1,32 @@
-+#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
-diff --git a/src/modules/volume-api/volume-api.c b/src/modules/volume-api/volume-api.c
-new file mode 100644
-index 0000000..9abea7e
---- /dev/null
-+++ b/src/modules/volume-api/volume-api.c
-@@ -0,0 +1,647 @@
-+/***
-+ 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/binding.h>
-+#include <modules/volume-api/device.h>
-+#include <modules/volume-api/device-creator.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/shared.h>
-+
-+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);
-+ }
-+}
-+
-+void pa_volume_api_add_binding_target_type(pa_volume_api *api, pa_binding_target_type *type) {
-+ pa_assert(api);
-+ pa_assert(type);
-+
-+ pa_assert_se(pa_hashmap_put(api->binding_target_types, type->name, type) >= 0);
-+
-+ pa_log_debug("Added binding target type %s.", type->name);
-+
-+ pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_ADDED], type);
-+}
-+
-+void pa_volume_api_remove_binding_target_type(pa_volume_api *api, pa_binding_target_type *type) {
-+ pa_assert(api);
-+ pa_assert(type);
-+
-+ pa_log_debug("Removing binding target type %s.", type->name);
-+
-+ pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_REMOVED], type);
-+
-+ pa_assert_se(pa_hashmap_remove(api->binding_target_types, type->name));
-+}
-+
-+static void create_builtin_binding_target_types(pa_volume_api *api) {
-+ pa_binding_target_type *type;
-+
-+ pa_assert(api);
-+
-+ type = pa_audio_group_create_binding_target_type(api);
-+ pa_volume_api_add_binding_target_type(api, type);
-+}
-+
-+static void delete_builtin_binding_target_types(pa_volume_api *api) {
-+ pa_binding_target_type *type;
-+
-+ pa_assert(api);
-+
-+ type = pa_hashmap_get(api->binding_target_types, PA_AUDIO_GROUP_BINDING_TARGET_TYPE);
-+ pa_volume_api_remove_binding_target_type(api, type);
-+}
-+
-+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->binding_target_types = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-+ 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_builtin_binding_target_types(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.");
-+
-+ 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);
-+
-+ if (api->binding_target_types)
-+ delete_builtin_binding_target_types(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_assert(pa_hashmap_isempty(api->mute_controls));
-+ pa_hashmap_free(api->mute_controls);
-+ }
-+
-+ if (api->volume_controls) {
-+ pa_assert(pa_hashmap_isempty(api->volume_controls));
-+ pa_hashmap_free(api->volume_controls);
-+ }
-+
-+ if (api->names) {
-+ pa_assert(pa_hashmap_isempty(api->names));
-+ pa_hashmap_free(api->names);
-+ }
-+
-+ if (api->binding_target_types) {
-+ pa_assert(pa_hashmap_isempty(api->binding_target_types));
-+ pa_hashmap_free(api->binding_target_types);
-+ }
-+
-+ 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);
-+
-+ n = pa_xstrdup(requested_name);
-+
-+ if (pa_hashmap_put(api->names, n, n) < 0) {
-+ unsigned i = 1;
-+
-+ pa_xfree(n);
-+
-+ if (fail_if_already_registered) {
-+ pa_log("Name %s already registered.", requested_name);
-+ return -PA_ERR_EXIST;
-+ }
-+
-+ do {
-+ 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;
-+}
-+
-+static void set_main_output_volume_control_internal(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);
-+}
-+
-+static void set_main_input_volume_control_internal(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_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)
-+ set_main_output_volume_control_internal(api, NULL);
-+
-+ if (control == api->main_input_volume_control)
-+ set_main_input_volume_control_internal(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;
-+}
-+
-+static void set_main_output_mute_control_internal(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);
-+}
-+
-+static void set_main_input_mute_control_internal(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);
-+}
-+
-+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)
-+ set_main_output_mute_control_internal(api, NULL);
-+
-+ if (control == api->main_input_mute_control)
-+ set_main_input_mute_control_internal(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_assert(api);
-+
-+ if (api->main_output_volume_control_binding) {
-+ pa_binding_free(api->main_output_volume_control_binding);
-+ api->main_output_volume_control_binding = NULL;
-+ }
-+
-+ set_main_output_volume_control_internal(api, control);
-+}
-+
-+void pa_volume_api_set_main_input_volume_control(pa_volume_api *api, pa_volume_control *control) {
-+ pa_assert(api);
-+
-+ if (api->main_input_volume_control_binding) {
-+ pa_binding_free(api->main_input_volume_control_binding);
-+ api->main_input_volume_control_binding = NULL;
-+ }
-+
-+ set_main_input_volume_control_internal(api, control);
-+}
-+
-+void pa_volume_api_set_main_output_mute_control(pa_volume_api *api, pa_mute_control *control) {
-+ pa_assert(api);
-+
-+ if (api->main_output_mute_control_binding) {
-+ pa_binding_free(api->main_output_mute_control_binding);
-+ api->main_output_mute_control_binding = NULL;
-+ }
-+
-+ set_main_output_mute_control_internal(api, control);
-+}
-+
-+void pa_volume_api_set_main_input_mute_control(pa_volume_api *api, pa_mute_control *control) {
-+ pa_assert(api);
-+
-+ if (api->main_input_mute_control_binding) {
-+ pa_binding_free(api->main_input_mute_control_binding);
-+ api->main_input_mute_control_binding = NULL;
-+ }
-+
-+ set_main_input_mute_control_internal(api, control);
-+}
-+
-+void pa_volume_api_bind_main_output_volume_control(pa_volume_api *api, pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = api,
-+ .set_value = (pa_binding_set_value_cb_t) set_main_output_volume_control_internal,
-+ };
-+
-+ pa_assert(api);
-+ pa_assert(target_info);
-+
-+ if (api->main_output_volume_control_binding)
-+ pa_binding_free(api->main_output_volume_control_binding);
-+
-+ api->main_output_volume_control_binding = pa_binding_new(api, &owner_info, target_info);
-+}
-+
-+void pa_volume_api_bind_main_input_volume_control(pa_volume_api *api, pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = api,
-+ .set_value = (pa_binding_set_value_cb_t) set_main_input_volume_control_internal,
-+ };
-+
-+ pa_assert(api);
-+ pa_assert(target_info);
-+
-+ if (api->main_input_volume_control_binding)
-+ pa_binding_free(api->main_input_volume_control_binding);
-+
-+ api->main_input_volume_control_binding = pa_binding_new(api, &owner_info, target_info);
-+}
-+
-+void pa_volume_api_bind_main_output_mute_control(pa_volume_api *api, pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = api,
-+ .set_value = (pa_binding_set_value_cb_t) set_main_output_mute_control_internal,
-+ };
-+
-+ pa_assert(api);
-+ pa_assert(target_info);
-+
-+ if (api->main_output_mute_control_binding)
-+ pa_binding_free(api->main_output_mute_control_binding);
-+
-+ api->main_output_mute_control_binding = pa_binding_new(api, &owner_info, target_info);
-+}
-+
-+void pa_volume_api_bind_main_input_mute_control(pa_volume_api *api, pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = api,
-+ .set_value = (pa_binding_set_value_cb_t) set_main_input_mute_control_internal,
-+ };
-+
-+ pa_assert(api);
-+ pa_assert(target_info);
-+
-+ if (api->main_input_mute_control_binding)
-+ pa_binding_free(api->main_input_mute_control_binding);
-+
-+ api->main_input_mute_control_binding = pa_binding_new(api, &owner_info, target_info);
-+}
-diff --git a/src/modules/volume-api/volume-api.h b/src/modules/volume-api/volume-api.h
-new file mode 100644
-index 0000000..73a1410
---- /dev/null
-+++ b/src/modules/volume-api/volume-api.h
-@@ -0,0 +1,163 @@
-+#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>
-+
-+typedef struct pa_volume_api pa_volume_api;
-+
-+/* Avoid circular dependencies... */
-+typedef struct pa_audio_group pa_audio_group;
-+typedef struct pa_binding pa_binding;
-+typedef struct pa_binding_target_info pa_binding_target_info;
-+typedef struct pa_binding_target_type pa_binding_target_type;
-+typedef struct pa_device pa_device;
-+typedef struct pa_device_creator pa_device_creator;
-+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 {
-+ PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_ADDED,
-+ PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_REMOVED,
-+ 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_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,
-+
-+ /* Policy modules can use this to set the initial volume control for a
-+ * stream. The hook callback should use pas_stream_set_volume_control() to
-+ * set the volume control. The hook callback should not do anything if
-+ * stream->volume_control is already non-NULL. */
-+ PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_VOLUME_CONTROL,
-+
-+ /* Policy modules can use this to set the initial mute control for a
-+ * stream. The hook callback should use pas_stream_set_mute_control() to
-+ * set the mute control. The hook callback should not do anything if
-+ * stream->mute_control is already non-NULL. */
-+ PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_MUTE_CONTROL,
-+
-+ PA_VOLUME_API_HOOK_STREAM_PUT,
-+ PA_VOLUME_API_HOOK_STREAM_UNLINK,
-+ PA_VOLUME_API_HOOK_STREAM_DESCRIPTION_CHANGED,
-+ PA_VOLUME_API_HOOK_STREAM_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_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 *binding_target_types; /* name -> pa_binding_target_type */
-+ 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_binding *main_output_volume_control_binding;
-+ pa_binding *main_input_volume_control_binding;
-+ pa_binding *main_output_mute_control_binding;
-+ pa_binding *main_input_mute_control_binding;
-+ pa_hook hooks[PA_VOLUME_API_HOOK_MAX];
-+ pa_defer_event *create_objects_defer_event;
-+ pa_device_creator *device_creator;
-+ pa_stream_creator *stream_creator;
-+};
-+
-+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);
-+
-+void pa_volume_api_add_binding_target_type(pa_volume_api *api, pa_binding_target_type *type);
-+void pa_volume_api_remove_binding_target_type(pa_volume_api *api, pa_binding_target_type *type);
-+
-+/* If fail_if_already_registered is false, this function never fails. */
-+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);
-+void pa_volume_api_bind_main_output_volume_control(pa_volume_api *api, pa_binding_target_info *target_info);
-+void pa_volume_api_bind_main_input_volume_control(pa_volume_api *api, pa_binding_target_info *target_info);
-+void pa_volume_api_bind_main_output_mute_control(pa_volume_api *api, pa_binding_target_info *target_info);
-+void pa_volume_api_bind_main_input_mute_control(pa_volume_api *api, pa_binding_target_info *target_info);
-+
-+#endif
-diff --git a/src/modules/volume-api/volume-control.c b/src/modules/volume-api/volume-control.c
-new file mode 100644
-index 0000000..c7f5dbb
---- /dev/null
-+++ b/src/modules/volume-api/volume-control.c
-@@ -0,0 +1,363 @@
-+/***
-+ 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/sstream.h>
-+
-+#include <pulsecore/core-util.h>
-+
-+pa_volume_control *pa_volume_control_new(pa_volume_api *api, const char *name, const char *description, bool convertible_to_dB,
-+ bool channel_map_is_writable) {
-+ pa_volume_control *control;
-+
-+ pa_assert(api);
-+ pa_assert(name);
-+ pa_assert(description);
-+
-+ control = pa_xnew0(pa_volume_control, 1);
-+ control->volume_api = api;
-+ control->index = pa_volume_api_allocate_volume_control_index(api);
-+ pa_assert_se(pa_volume_api_register_name(api, name, false, &control->name) >= 0);
-+ control->description = pa_xstrdup(description);
-+ control->proplist = pa_proplist_new();
-+ pa_bvolume_init_invalid(&control->volume);
-+ control->convertible_to_dB = convertible_to_dB;
-+ control->channel_map_is_writable = channel_map_is_writable;
-+ control->devices = pa_hashmap_new(NULL, NULL);
-+ control->default_for_devices = pa_hashmap_new(NULL, NULL);
-+ control->streams = pa_hashmap_new(NULL, NULL);
-+ control->audio_groups = pa_hashmap_new(NULL, NULL);
-+
-+ return control;
-+}
-+
-+void pa_volume_control_put(pa_volume_control *control, const pa_bvolume *initial_volume,
-+ pa_volume_control_set_initial_volume_cb_t set_initial_volume_cb) {
-+ 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((initial_volume && pa_bvolume_valid(initial_volume, true, true)) || control->set_volume);
-+ pa_assert((initial_volume && pa_channel_map_valid(&initial_volume->channel_map)) || control->channel_map_is_writable);
-+ pa_assert(set_initial_volume_cb || !control->set_volume);
-+
-+ if (initial_volume && pa_bvolume_valid(initial_volume, true, false))
-+ control->volume.volume = initial_volume->volume;
-+ else
-+ control->volume.volume = PA_VOLUME_NORM / 3;
-+
-+ if (initial_volume && pa_bvolume_valid(initial_volume, false, true))
-+ pa_bvolume_copy_balance(&control->volume, initial_volume);
-+ else if (initial_volume && pa_channel_map_valid(&initial_volume->channel_map))
-+ pa_bvolume_reset_balance(&control->volume, &initial_volume->channel_map);
-+ else {
-+ pa_channel_map_init_mono(&control->volume.channel_map);
-+ pa_bvolume_reset_balance(&control->volume, &control->volume.channel_map);
-+ }
-+
-+ if (set_initial_volume_cb)
-+ set_initial_volume_cb(control);
-+
-+ 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(" 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_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(" Channel map is writable: %s", pa_yes_no(control->channel_map_is_writable));
-+
-+ 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_audio_group *group;
-+ pa_device *device;
-+ pas_stream *stream;
-+
-+ 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_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK], control);
-+
-+ pa_volume_api_remove_volume_control(control->volume_api, control);
-+
-+ while ((group = pa_hashmap_first(control->audio_groups)))
-+ pa_audio_group_set_volume_control(group, NULL);
-+
-+ while ((stream = pa_hashmap_first(control->streams)))
-+ pas_stream_set_volume_control(stream, NULL);
-+
-+ 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);
-+
-+ if (!control->unlinked)
-+ pa_volume_control_unlink(control);
-+
-+ if (control->audio_groups) {
-+ pa_assert(pa_hashmap_isempty(control->audio_groups));
-+ pa_hashmap_free(control->audio_groups);
-+ }
-+
-+ if (control->streams) {
-+ pa_assert(pa_hashmap_isempty(control->streams));
-+ pa_hashmap_free(control->streams);
-+ }
-+
-+ 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_owner_audio_group(pa_volume_control *control, pa_audio_group *group) {
-+ pa_assert(control);
-+ pa_assert(group);
-+
-+ control->owner_audio_group = group;
-+}
-+
-+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;
-+
-+ 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 (balance_changed)
-+ pa_bvolume_copy_balance(&control->volume, volume);
-+
-+ 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);
-+
-+ volume_local = *volume;
-+
-+ if (!control->set_volume) {
-+ pa_log_info("Tried to set the volume of volume control %s, but the volume control doesn't support the operation.",
-+ control->name);
-+ return -PA_ERR_NOTSUPPORTED;
-+ }
-+
-+ if (set_balance
-+ && !control->channel_map_is_writable
-+ && !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;
-+
-+ control->set_volume_in_progress = true;
-+ r = control->set_volume(control, &volume_local, set_volume, set_balance);
-+ control->set_volume_in_progress = false;
-+
-+ if (r >= 0)
-+ set_volume_internal(control, &volume_local, set_volume, set_balance);
-+
-+ return r;
-+}
-+
-+void pa_volume_control_description_changed(pa_volume_control *control, const char *new_description) {
-+ char *old_description;
-+
-+ pa_assert(control);
-+ pa_assert(new_description);
-+
-+ old_description = control->description;
-+
-+ if (pa_streq(new_description, old_description))
-+ return;
-+
-+ control->description = pa_xstrdup(new_description);
-+ pa_log_debug("The description of volume control %s changed from \"%s\" to \"%s\".", control->name, old_description,
-+ new_description);
-+ pa_xfree(old_description);
-+ pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_DESCRIPTION_CHANGED], control);
-+}
-+
-+void pa_volume_control_volume_changed(pa_volume_control *control, const pa_bvolume *new_volume, bool volume_changed,
-+ bool balance_changed) {
-+ pa_assert(control);
-+ pa_assert(new_volume);
-+
-+ if (!control->linked)
-+ return;
-+
-+ if (control->set_volume_in_progress)
-+ return;
-+
-+ set_volume_internal(control, new_volume, volume_changed, balance_changed);
-+}
-+
-+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));
-+}
-+
-+void pa_volume_control_add_stream(pa_volume_control *control, pas_stream *stream) {
-+ pa_assert(control);
-+ pa_assert(stream);
-+
-+ pa_assert_se(pa_hashmap_put(control->streams, stream, stream) >= 0);
-+}
-+
-+void pa_volume_control_remove_stream(pa_volume_control *control, pas_stream *stream) {
-+ pa_assert(control);
-+ pa_assert(stream);
-+
-+ pa_assert_se(pa_hashmap_remove(control->streams, stream));
-+}
-+
-+void pa_volume_control_add_audio_group(pa_volume_control *control, pa_audio_group *group) {
-+ pa_assert(control);
-+ pa_assert(group);
-+
-+ pa_assert_se(pa_hashmap_put(control->audio_groups, group, group) >= 0);
-+}
-+
-+void pa_volume_control_remove_audio_group(pa_volume_control *control, pa_audio_group *group) {
-+ pa_assert(control);
-+ pa_assert(group);
-+
-+ pa_assert_se(pa_hashmap_remove(control->audio_groups, group));
-+}
-diff --git a/src/modules/volume-api/volume-control.h b/src/modules/volume-api/volume-control.h
-new file mode 100644
-index 0000000..aaba758
---- /dev/null
-+++ b/src/modules/volume-api/volume-control.h
-@@ -0,0 +1,112 @@
-+#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/volume-api.h>
-+
-+typedef struct pa_volume_control pa_volume_control;
-+
-+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 channel_map_is_writable;
-+
-+ /* If this volume control is the "own volume 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) */
-+ pa_hashmap *streams; /* pas_stream -> pas_stream (hashmap-as-a-set) */
-+ pa_hashmap *audio_groups; /* pa_audio_group -> pa_audio_group (hashmap-as-a-set) */
-+
-+ 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. May be NULL, if the
-+ * volume control is read-only. */
-+ int (*set_volume)(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance);
-+
-+ void *userdata;
-+};
-+
-+pa_volume_control *pa_volume_control_new(pa_volume_api *api, const char *name, const char *description, bool convertible_to_dB,
-+ bool channel_map_is_writable);
-+
-+typedef void (*pa_volume_control_set_initial_volume_cb_t)(pa_volume_control *control);
-+
-+/* initial_volume is the preferred initial volume of the volume control
-+ * implementation. It may be NULL or partially invalid, if the implementation
-+ * doesn't care about the initial state of the volume control, as long as these
-+ * two rules are followed:
-+ *
-+ * 1) Read-only volume controls must always specify fully valid initial
-+ * volume.
-+ * 2) Volume controls with read-only channel map must always specify a valid
-+ * channel map in initial_volume.
-+ *
-+ * The implementation's initial volume preference may be overridden by policy,
-+ * if the volume control isn't read-only. When the final initial volume is
-+ * known, the implementation is notified via set_initial_volume_cb (the volume
-+ * can be read from control->volume). set_initial_volume_cb may be NULL, if the
-+ * volume control is read-only. */
-+void pa_volume_control_put(pa_volume_control *control, const pa_bvolume *initial_volume,
-+ pa_volume_control_set_initial_volume_cb_t set_initial_volume_cb);
-+
-+void pa_volume_control_unlink(pa_volume_control *control);
-+void pa_volume_control_free(pa_volume_control *control);
-+
-+/* Called by audio-group.c only. */
-+void pa_volume_control_set_owner_audio_group(pa_volume_control *control, pa_audio_group *group);
-+
-+/* Called by clients and policy modules. */
-+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_description_changed(pa_volume_control *control, const char *new_description);
-+void pa_volume_control_volume_changed(pa_volume_control *control, const pa_bvolume *new_volume, bool volume_changed,
-+ bool balance_changed);
-+
-+/* 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);
-+
-+/* Called from sstream.c only. */
-+void pa_volume_control_add_stream(pa_volume_control *control, pas_stream *stream);
-+void pa_volume_control_remove_stream(pa_volume_control *control, pas_stream *stream);
-+
-+/* Called from audio-group.c only. */
-+void pa_volume_control_add_audio_group(pa_volume_control *control, pa_audio_group *group);
-+void pa_volume_control_remove_audio_group(pa_volume_control *control, pa_audio_group *group);
-+
-+#endif
-diff --git a/src/pulse/ext-volume-api.c b/src/pulse/ext-volume-api.c
-new file mode 100644
-index 0000000..8e93bce
---- /dev/null
-+++ b/src/pulse/ext-volume-api.c
-@@ -0,0 +1,275 @@
-+/***
-+ 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 <pulsecore/core-util.h>
-+#include <pulsecore/i18n.h>
-+#include <pulsecore/macro.h>
-+
-+#include <math.h>
-+
-+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_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_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;
-+}
-+
-+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;
-+}
-diff --git a/src/pulse/ext-volume-api.h b/src/pulse/ext-volume-api.h
-new file mode 100644
-index 0000000..36b7748
---- /dev/null
-+++ b/src/pulse/ext-volume-api.h
-@@ -0,0 +1,68 @@
-+#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;
-+
-+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_mono(pa_ext_volume_api_bvolume *bvolume, pa_volume_t volume);
-+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);
-+
-+#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);
-+
-+PA_C_DECL_END
-+
-+#endif
---
-2.1.4
-
---- a/po/POTFILES.in 2016-04-13 17:40:00.818008672 +0200
-+++ b/po/POTFILES.in 2016-04-13 17:40:30.885008622 +0200
-@@ -198,3 +198,5 @@
- src/utils/padsp.c
- src/utils/pasuspender.c
- src/utils/pax11publish.c
-+src/modules/volume-api/device-creator.c
-+src/pulse/ext-volume-api.c
diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0031-Add-module-main-volume-policy.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0031-Add-module-main-volume-policy.patch
deleted file mode 100644
index 216ed21e9..000000000
--- a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0031-Add-module-main-volume-policy.patch
+++ /dev/null
@@ -1,1418 +0,0 @@
-From cfb39f18569679f59c9b6283c47e8d90ddd9763d Mon Sep 17 00:00:00 2001
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 21 May 2014 14:13:41 +0300
-Subject: [PATCH] Add module-main-volume-policy
-
-Change-Id: I787141b43cafb652aa752c64ae28b6b7aa052d8e
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- Makefile.am | 3 +
- src/Makefile.am | 15 +
- src/daemon/default.pa.in | 4 +
- .../main-volume-policy/main-volume-context.c | 325 ++++++++++++
- .../main-volume-policy/main-volume-context.h | 75 +++
- .../main-volume-policy/main-volume-policy.c | 213 ++++++++
- .../main-volume-policy.conf.example | 20 +
- .../main-volume-policy/main-volume-policy.h | 72 +++
- .../main-volume-policy/module-main-volume-policy.c | 556 +++++++++++++++++++++
- 9 files changed, 1283 insertions(+)
- create mode 100644 src/modules/main-volume-policy/main-volume-context.c
- create mode 100644 src/modules/main-volume-policy/main-volume-context.h
- create mode 100644 src/modules/main-volume-policy/main-volume-policy.c
- create mode 100644 src/modules/main-volume-policy/main-volume-policy.conf.example
- create mode 100644 src/modules/main-volume-policy/main-volume-policy.h
- create mode 100644 src/modules/main-volume-policy/module-main-volume-policy.c
-
-diff --git a/Makefile.am b/Makefile.am
-index cf4a648..646b7fc 100644
---- a/Makefile.am 2016-04-13 15:14:28.942023245 +0200
-+++ b/Makefile.am 2016-04-13 15:16:32.691023039 +0200
-@@ -60,6 +60,9 @@
- moduledevvolumeapi_DATA = src/modules/volume-api/*.h
- moduledevvolumeapidir = $(includedir)/pulsemodule/modules/volume-api
-
-+moduledevmainvolumepolicy_DATA = $(top_srcdir)/src/modules/main-volume-policy/*.h
-+moduledevmainvolumepolicydir = $(includedir)/pulsemodule/modules/main-volume-policy
-+
- if HAVE_GLIB20
- pkgconfig_DATA += \
- libpulse-mainloop-glib.pc
- libpulse-mainloop-glib.pc
-diff --git a/src/Makefile.am b/src/Makefile.am
-index a6bb319..8fa60ec 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -1050,7 +1050,8 @@
- libprotocol-simple.la \
- libprotocol-http.la \
- libprotocol-native.la \
-- libvolume-api.la
-+ libvolume-api.la \
-+ libmain-volume-policy.la
-
- if HAVE_WEBRTC
- modlibexec_LTLIBRARIES += libwebrtc-util.la
-@@ -1051,6 +1052,12 @@ libcli_la_SOURCES = pulsecore/cli.c pulsecore/cli.h
- libcli_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
- libcli_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
-@@ -1136,6 +1136,7 @@ endif
- modlibexec_LTLIBRARIES += \
- module-cli.la \
- module-cli-protocol-tcp.la \
-+ module-main-volume-policy.la \
- module-simple-protocol-tcp.la \
- module-null-sink.la \
- module-null-source.la \
-@@ -1426,6 +1434,7 @@ SYMDEF_FILES = \
- 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 \
-@@ -1575,6 +1584,12 @@ module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_
- 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
-diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
-index 7cf52a4..f70804c 100755
---- a/src/daemon/default.pa.in
-+++ b/src/daemon/default.pa.in
-@@ -188,6 +188,10 @@
- #.endif
- ])dnl
-
-+.ifexists module-main-volume-policy
-+load-module module-main-volume-policy
-+.endif
-+
- ### Make some devices default
- #set-default-sink output
- #set-default-source input
-diff --git a/src/modules/main-volume-policy/main-volume-context.c b/src/modules/main-volume-policy/main-volume-context.c
-new file mode 100644
-index 0000000..7ac35c6
---- /dev/null
-+++ b/src/modules/main-volume-policy/main-volume-context.c
-@@ -0,0 +1,325 @@
-+/***
-+ 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>
-+
-+int pa_main_volume_context_new(pa_main_volume_policy *policy, const char *name, const char *description,
-+ pa_main_volume_context **context) {
-+ pa_main_volume_context *context_local;
-+ int r;
-+
-+ pa_assert(policy);
-+ pa_assert(name);
-+ pa_assert(description);
-+ pa_assert(context);
-+
-+ context_local = pa_xnew0(struct pa_main_volume_context, 1);
-+ context_local->main_volume_policy = policy;
-+ context_local->index = pa_main_volume_policy_allocate_main_volume_context_index(policy);
-+
-+ r = pa_main_volume_policy_register_name(policy, name, true, &context_local->name);
-+ if (r < 0)
-+ goto fail;
-+
-+ context_local->description = pa_xstrdup(description);
-+
-+ *context = context_local;
-+
-+ return 0;
-+
-+fail:
-+ pa_main_volume_context_free(context_local);
-+
-+ 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_hook_fire(&context->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK], context);
-+
-+ if (context->main_input_mute_control_binding) {
-+ pa_binding_free(context->main_input_mute_control_binding);
-+ context->main_input_mute_control_binding = NULL;
-+ }
-+
-+ if (context->main_output_mute_control_binding) {
-+ pa_binding_free(context->main_output_mute_control_binding);
-+ context->main_output_mute_control_binding = NULL;
-+ }
-+
-+ if (context->main_input_volume_control_binding) {
-+ pa_binding_free(context->main_input_volume_control_binding);
-+ context->main_input_volume_control_binding = NULL;
-+ }
-+
-+ if (context->main_output_volume_control_binding) {
-+ pa_binding_free(context->main_output_volume_control_binding);
-+ context->main_output_volume_control_binding = NULL;
-+ }
-+
-+ context->main_input_mute_control = NULL;
-+ context->main_output_mute_control = NULL;
-+ context->main_input_volume_control = NULL;
-+ context->main_output_volume_control = NULL;
-+
-+ pa_main_volume_policy_remove_main_volume_context(context->main_volume_policy, context);
-+}
-+
-+void pa_main_volume_context_free(pa_main_volume_context *context) {
-+ pa_assert(context);
-+
-+ if (!context->unlinked)
-+ 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);
-+}
-+
-+const char *pa_main_volume_context_get_name(pa_main_volume_context *context) {
-+ pa_assert(context);
-+
-+ return context->name;
-+}
-+
-+static void set_main_output_volume_control_internal(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("The main output volume control of main volume context %s 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_bind_main_output_volume_control(pa_main_volume_context *context,
-+ pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = context,
-+ .set_value = (pa_binding_set_value_cb_t) set_main_output_volume_control_internal,
-+ };
-+
-+ pa_assert(context);
-+ pa_assert(target_info);
-+
-+ if (context->main_output_volume_control_binding)
-+ pa_binding_free(context->main_output_volume_control_binding);
-+
-+ context->main_output_volume_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info,
-+ target_info);
-+}
-+
-+static void set_main_input_volume_control_internal(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("The main input volume control of main volume context %s 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_bind_main_input_volume_control(pa_main_volume_context *context,
-+ pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = context,
-+ .set_value = (pa_binding_set_value_cb_t) set_main_input_volume_control_internal,
-+ };
-+
-+ pa_assert(context);
-+ pa_assert(target_info);
-+
-+ if (context->main_input_volume_control_binding)
-+ pa_binding_free(context->main_input_volume_control_binding);
-+
-+ context->main_input_volume_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info,
-+ target_info);
-+}
-+
-+static void set_main_output_mute_control_internal(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("The main output mute control of main volume context %s 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_bind_main_output_mute_control(pa_main_volume_context *context,
-+ pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = context,
-+ .set_value = (pa_binding_set_value_cb_t) set_main_output_mute_control_internal,
-+ };
-+
-+ pa_assert(context);
-+ pa_assert(target_info);
-+
-+ if (context->main_output_mute_control_binding)
-+ pa_binding_free(context->main_output_mute_control_binding);
-+
-+ context->main_output_mute_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info,
-+ target_info);
-+}
-+
-+static void set_main_input_mute_control_internal(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("The main input mute control of main volume context %s 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);
-+}
-+
-+void pa_main_volume_context_bind_main_input_mute_control(pa_main_volume_context *context,
-+ pa_binding_target_info *target_info) {
-+ pa_binding_owner_info owner_info = {
-+ .userdata = context,
-+ .set_value = (pa_binding_set_value_cb_t) set_main_input_mute_control_internal,
-+ };
-+
-+ pa_assert(context);
-+ pa_assert(target_info);
-+
-+ if (context->main_input_mute_control_binding)
-+ pa_binding_free(context->main_input_mute_control_binding);
-+
-+ context->main_input_mute_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info,
-+ target_info);
-+}
-+
-+pa_binding_target_type *pa_main_volume_context_create_binding_target_type(pa_main_volume_policy *policy) {
-+ pa_binding_target_type *type;
-+
-+ pa_assert(policy);
-+
-+ type = pa_binding_target_type_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, policy->main_volume_contexts,
-+ &policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_PUT],
-+ &policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK],
-+ (pa_binding_target_type_get_name_cb_t) pa_main_volume_context_get_name);
-+ pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_VOLUME_CONTROL,
-+ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_output_volume_control));
-+ pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_VOLUME_CONTROL,
-+ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_input_volume_control));
-+ pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_MUTE_CONTROL,
-+ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_output_mute_control));
-+ pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_MUTE_CONTROL,
-+ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_input_mute_control));
-+
-+ return type;
-+}
-diff --git a/src/modules/main-volume-policy/main-volume-context.h b/src/modules/main-volume-policy/main-volume-context.h
-new file mode 100644
-index 0000000..4a0a6f7
---- /dev/null
-+++ b/src/modules/main-volume-policy/main-volume-context.h
-@@ -0,0 +1,75 @@
-+#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>
-+
-+#include <modules/volume-api/binding.h>
-+
-+typedef struct pa_main_volume_context pa_main_volume_context;
-+
-+#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE "MainVolumeContext"
-+#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_VOLUME_CONTROL "main_output_volume_control"
-+#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_VOLUME_CONTROL "main_input_volume_control"
-+#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_MUTE_CONTROL "main_output_mute_control"
-+#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_MUTE_CONTROL "main_input_mute_control"
-+
-+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;
-+
-+ pa_binding *main_output_volume_control_binding;
-+ pa_binding *main_input_volume_control_binding;
-+ pa_binding *main_output_mute_control_binding;
-+ pa_binding *main_input_mute_control_binding;
-+
-+ bool linked;
-+ bool unlinked;
-+};
-+
-+int pa_main_volume_context_new(pa_main_volume_policy *policy, const char *name, const char *description,
-+ pa_main_volume_context **context);
-+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);
-+
-+const char *pa_main_volume_context_get_name(pa_main_volume_context *context);
-+
-+void pa_main_volume_context_bind_main_output_volume_control(pa_main_volume_context *context,
-+ pa_binding_target_info *target_info);
-+void pa_main_volume_context_bind_main_input_volume_control(pa_main_volume_context *context,
-+ pa_binding_target_info *target_info);
-+void pa_main_volume_context_bind_main_output_mute_control(pa_main_volume_context *context,
-+ pa_binding_target_info *target_info);
-+void pa_main_volume_context_bind_main_input_mute_control(pa_main_volume_context *context, pa_binding_target_info *target_info);
-+
-+/* Called from main-volume-policy.c only. */
-+pa_binding_target_type *pa_main_volume_context_create_binding_target_type(pa_main_volume_policy *policy);
-+
-+#endif
-diff --git a/src/modules/main-volume-policy/main-volume-policy.c b/src/modules/main-volume-policy/main-volume-policy.c
-new file mode 100644
-index 0000000..b0b4ede
---- /dev/null
-+++ b/src/modules/main-volume-policy/main-volume-policy.c
-@@ -0,0 +1,213 @@
-+/***
-+ 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/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_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->main_volume_context_binding_target_type = pa_main_volume_context_create_binding_target_type(policy);
-+ pa_volume_api_add_binding_target_type(policy->volume_api, policy->main_volume_context_binding_target_type);
-+
-+ 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->main_volume_context_binding_target_type) {
-+ pa_volume_api_remove_binding_target_type(policy->volume_api, policy->main_volume_context_binding_target_type);
-+ pa_binding_target_type_free(policy->main_volume_context_binding_target_type);
-+ }
-+
-+ 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);
-+
-+ n = pa_xstrdup(requested_name);
-+
-+ if (pa_hashmap_put(policy->names, n, n) < 0) {
-+ unsigned i = 1;
-+
-+ pa_xfree(n);
-+
-+ if (fail_if_already_registered) {
-+ pa_log("Name %s already registered.", requested_name);
-+ return -PA_ERR_EXIST;
-+ }
-+
-+ do {
-+ 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);
-+}
-diff --git a/src/modules/main-volume-policy/main-volume-policy.conf.example b/src/modules/main-volume-policy/main-volume-policy.conf.example
-new file mode 100644
-index 0000000..a4a35d3
---- /dev/null
-+++ b/src/modules/main-volume-policy/main-volume-policy.conf.example
-@@ -0,0 +1,20 @@
-+[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
-+main-volume-contexts = x-example-call-main-volume-context x-example-default-main-volume-context
-+
-+[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
-diff --git a/src/modules/main-volume-policy/main-volume-policy.h b/src/modules/main-volume-policy/main-volume-policy.h
-new file mode 100644
-index 0000000..5cd669e
---- /dev/null
-+++ b/src/modules/main-volume-policy/main-volume-policy.h
-@@ -0,0 +1,72 @@
-+#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/binding.h>
-+#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_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_binding_target_type *main_volume_context_binding_target_type;
-+};
-+
-+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
-diff --git a/src/modules/main-volume-policy/module-main-volume-policy.c b/src/modules/main-volume-policy/module-main-volume-policy.c
-new file mode 100644
-index 0000000..a14699d
---- /dev/null
-+++ b/src/modules/main-volume-policy/module-main-volume-policy.c
-@@ -0,0 +1,556 @@
-+/***
-+ 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/binding.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>
-+
-+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_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;
-+
-+ /* The following fields are only used during initialization. */
-+ pa_hashmap *context_names; /* name -> name (hashmap-as-a-set) */
-+ pa_hashmap *unused_contexts; /* name -> struct context */
-+};
-+
-+struct context {
-+ struct userdata *userdata;
-+ char *name;
-+ char *description;
-+ pa_binding_target_info *main_output_volume_control_target_info;
-+ pa_binding_target_info *main_input_volume_control_target_info;
-+ pa_binding_target_info *main_output_mute_control_target_info;
-+ pa_binding_target_info *main_input_mute_control_target_info;
-+ pa_main_volume_context *main_volume_context;
-+
-+ bool unlinked;
-+};
-+
-+static void context_unlink(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 struct context *context_new(struct userdata *u, const char *name) {
-+ struct context *context;
-+
-+ pa_assert(u);
-+ pa_assert(name);
-+
-+ context = pa_xnew0(struct context, 1);
-+ context->userdata = u;
-+ context->name = pa_xstrdup(name);
-+ context->description = pa_xstrdup(name);
-+
-+ return context;
-+}
-+
-+static int context_put(struct context *context) {
-+ int r;
-+
-+ pa_assert(context);
-+
-+ r = pa_main_volume_context_new(context->userdata->main_volume_policy, context->name, context->description,
-+ &context->main_volume_context);
-+ if (r < 0)
-+ goto fail;
-+
-+ if (context->main_output_volume_control_target_info)
-+ pa_main_volume_context_bind_main_output_volume_control(context->main_volume_context,
-+ context->main_output_volume_control_target_info);
-+
-+ if (context->main_input_volume_control_target_info)
-+ pa_main_volume_context_bind_main_input_volume_control(context->main_volume_context,
-+ context->main_input_volume_control_target_info);
-+
-+ if (context->main_output_mute_control_target_info)
-+ pa_main_volume_context_bind_main_output_mute_control(context->main_volume_context,
-+ context->main_output_mute_control_target_info);
-+
-+ if (context->main_input_mute_control_target_info)
-+ pa_main_volume_context_bind_main_input_mute_control(context->main_volume_context,
-+ context->main_input_mute_control_target_info);
-+
-+ pa_main_volume_context_put(context->main_volume_context);
-+
-+ return 0;
-+
-+fail:
-+ context_unlink(context);
-+
-+ return r;
-+}
-+
-+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_free(context->main_volume_context);
-+ context->main_volume_context = NULL;
-+ }
-+}
-+
-+static void context_free(struct context *context) {
-+ pa_assert(context);
-+
-+ if (!context->unlinked)
-+ context_unlink(context);
-+
-+ if (context->main_input_mute_control_target_info)
-+ pa_binding_target_info_free(context->main_input_mute_control_target_info);
-+
-+ if (context->main_output_mute_control_target_info)
-+ pa_binding_target_info_free(context->main_output_mute_control_target_info);
-+
-+ if (context->main_input_volume_control_target_info)
-+ pa_binding_target_info_free(context->main_input_volume_control_target_info);
-+
-+ if (context->main_output_volume_control_target_info)
-+ pa_binding_target_info_free(context->main_output_volume_control_target_info);
-+
-+ pa_xfree(context->description);
-+ pa_xfree(context->name);
-+ pa_xfree(context);
-+}
-+
-+static void context_set_description(struct context *context, const char *description) {
-+ pa_assert(context);
-+ pa_assert(description);
-+
-+ pa_xfree(context->description);
-+ context->description = pa_xstrdup(description);
-+}
-+
-+static void context_set_main_control_target_info(struct context *context, enum control_type type, pa_direction_t direction,
-+ pa_binding_target_info *info) {
-+ pa_assert(context);
-+
-+ switch (type) {
-+ case CONTROL_TYPE_VOLUME:
-+ if (direction == PA_DIRECTION_OUTPUT) {
-+ if (context->main_output_volume_control_target_info)
-+ pa_binding_target_info_free(context->main_output_volume_control_target_info);
-+
-+ if (info)
-+ context->main_output_volume_control_target_info = pa_binding_target_info_copy(info);
-+ else
-+ context->main_output_volume_control_target_info = NULL;
-+ } else {
-+ if (context->main_input_volume_control_target_info)
-+ pa_binding_target_info_free(context->main_input_volume_control_target_info);
-+
-+ if (info)
-+ context->main_input_volume_control_target_info = pa_binding_target_info_copy(info);
-+ else
-+ context->main_input_volume_control_target_info = NULL;
-+ }
-+ break;
-+
-+ case CONTROL_TYPE_MUTE:
-+ if (direction == PA_DIRECTION_OUTPUT) {
-+ if (context->main_output_mute_control_target_info)
-+ pa_binding_target_info_free(context->main_output_mute_control_target_info);
-+
-+ if (info)
-+ context->main_output_mute_control_target_info = pa_binding_target_info_copy(info);
-+ else
-+ context->main_output_mute_control_target_info = NULL;
-+ } else {
-+ if (context->main_input_mute_control_target_info)
-+ pa_binding_target_info_free(context->main_input_mute_control_target_info);
-+
-+ if (info)
-+ context->main_input_mute_control_target_info = pa_binding_target_info_copy(info);
-+ else
-+ context->main_input_mute_control_target_info = NULL;
-+ }
-+ break;
-+ }
-+}
-+
-+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_volume_api *api;
-+ pa_binding_target_info *info = NULL;
-+
-+ pa_assert(u);
-+
-+ context = u->main_volume_policy->active_main_volume_context;
-+ api = u->main_volume_policy->volume_api;
-+
-+ if (u->output_volume_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
-+ if (context) {
-+ info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name,
-+ PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_VOLUME_CONTROL);
-+ pa_volume_api_bind_main_output_volume_control(api, info);
-+ } else
-+ pa_volume_api_set_main_output_volume_control(api, NULL);
-+ }
-+
-+ if (u->input_volume_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
-+ if (context) {
-+ info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name,
-+ PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_VOLUME_CONTROL);
-+ pa_volume_api_bind_main_input_volume_control(api, info);
-+ } else
-+ pa_volume_api_set_main_input_volume_control(api, NULL);
-+ }
-+
-+ if (u->output_mute_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
-+ if (context) {
-+ info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name,
-+ PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_MUTE_CONTROL);
-+ pa_volume_api_bind_main_output_mute_control(api, info);
-+ } else
-+ pa_volume_api_set_main_output_mute_control(api, NULL);
-+ }
-+
-+ if (u->input_mute_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
-+ if (context) {
-+ info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name,
-+ PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_MUTE_CONTROL);
-+ pa_volume_api_bind_main_input_mute_control(api, info);
-+ } else
-+ pa_volume_api_set_main_input_mute_control(api, NULL);
-+ }
-+
-+ if (info)
-+ pa_binding_target_info_free(info);
-+
-+ 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 parse_main_volume_contexts(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)))
-+ pa_hashmap_put(u->context_names, name, name);
-+
-+ return 0;
-+}
-+
-+static struct context *get_context(struct userdata *u, const char *section) {
-+ const char *name;
-+ struct context *context;
-+
-+ pa_assert(u);
-+
-+ if (!section)
-+ return NULL;
-+
-+ if (!pa_startswith(section, "MainVolumeContext "))
-+ return NULL;
-+
-+ name = section + 18;
-+
-+ context = pa_hashmap_get(u->unused_contexts, name);
-+ if (!context) {
-+ context = context_new(u, name);
-+ pa_hashmap_put(u->unused_contexts, context->name, context);
-+ }
-+
-+ return context;
-+}
-+
-+static int parse_description(pa_config_parser_state *state) {
-+ struct userdata *u;
-+ struct context *context;
-+
-+ pa_assert(state);
-+
-+ u = state->userdata;
-+
-+ context = get_context(u, state->section);
-+ if (!context) {
-+ pa_log("[%s:%u] Key \"%s\" not expected in section %s.", state->filename, state->lineno, state->lvalue,
-+ pa_strnull(state->section));
-+ return -PA_ERR_INVALID;
-+ }
-+
-+ context_set_description(context, state->rvalue);
-+
-+ return 0;
-+}
-+
-+static const char *get_target_field_name(enum control_type type) {
-+ switch (type) {
-+ case CONTROL_TYPE_VOLUME:
-+ return "volume_control";
-+
-+ case CONTROL_TYPE_MUTE:
-+ return "mute_control";
-+ }
-+
-+ pa_assert_not_reached();
-+}
-+
-+static int parse_main_control(pa_config_parser_state *state, enum control_type type, pa_direction_t direction) {
-+ struct userdata *u;
-+ struct context *context;
-+
-+ pa_assert(state);
-+
-+ u = state->userdata;
-+
-+ context = get_context(u, state->section);
-+ if (!context) {
-+ pa_log("[%s:%u] Key \"%s\" not expected in section %s.", state->filename, state->lineno, state->lvalue,
-+ pa_strnull(state->section));
-+ return -PA_ERR_INVALID;
-+ }
-+
-+ if (pa_streq(state->rvalue, "none"))
-+ context_set_main_control_target_info(context, type, direction, NULL);
-+ else if (pa_startswith(state->rvalue, "bind:")) {
-+ int r;
-+ pa_binding_target_info *info;
-+
-+ r = pa_binding_target_info_new_from_string(state->rvalue, get_target_field_name(type), &info);
-+ if (r < 0) {
-+ pa_log("[%s:%u] Failed to parse binding target \"%s\".", state->filename, state->lineno, state->rvalue);
-+ return r;
-+ }
-+
-+ context_set_main_control_target_info(context, type, direction, info);
-+ pa_binding_target_info_free(info);
-+ } 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_main_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_main_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_main_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_main_control(state, CONTROL_TYPE_MUTE, PA_DIRECTION_INPUT);
-+}
-+
-+static void finalize_config(struct userdata *u) {
-+ const char *context_name;
-+ void *state;
-+ struct context *context;
-+
-+ pa_assert(u);
-+
-+ PA_HASHMAP_FOREACH(context_name, u->context_names, state) {
-+ int r;
-+
-+ context = pa_hashmap_remove(u->unused_contexts, context_name);
-+ if (!context)
-+ context = context_new(u, context_name);
-+
-+ r = context_put(context);
-+ if (r < 0) {
-+ pa_log_warn("Failed to create main volume context %s.", context_name);
-+ context_free(context);
-+ continue;
-+ }
-+
-+ pa_assert_se(pa_hashmap_put(u->contexts, context->name, context) >= 0);
-+ }
-+
-+ PA_HASHMAP_FOREACH(context, u->unused_contexts, state)
-+ pa_log_debug("Main volume context %s is not used.", context->name);
-+
-+ pa_hashmap_free(u->unused_contexts);
-+ u->unused_contexts = NULL;
-+
-+ pa_hashmap_free(u->context_names);
-+ u->context_names = NULL;
-+}
-+
-+int pa__init(pa_module *module) {
-+ struct userdata *u;
-+ FILE *f;
-+ char *fn = NULL;
-+
-+ pa_assert(module);
-+
-+ u = module->userdata = pa_xnew0(struct userdata, 1);
-+ 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->context_names = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
-+ u->unused_contexts = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
-+ (pa_free_cb_t) context_free);
-+
-+ 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" },
-+ { "main-volume-contexts", parse_main_volume_contexts, NULL, "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;
-+ }
-+
-+ finalize_config(u);
-+
-+ 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->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);
-+
-+ pa_xfree(u);
-+}
---
-2.1.4
-
---- a/po/POTFILES.in 2016-04-14 13:03:50.715006116 +0200
-+++ b/po/POTFILES.in 2016-04-14 13:04:23.097006062 +0200
-@@ -200,3 +200,4 @@
- src/utils/pax11publish.c
- src/modules/volume-api/device-creator.c
- src/pulse/ext-volume-api.c
-+src/modules/main-volume-policy/module-main-volume-policy.c
diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0039-main-volume-policy-adapt-to-pa6rev.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0039-main-volume-policy-adapt-to-pa6rev.patch
deleted file mode 100644
index 4f2777112..000000000
--- a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0039-main-volume-policy-adapt-to-pa6rev.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/src/modules/main-volume-policy/module-main-volume-policy.c 2016-04-18 10:59:46.124086205 +0200
-+++ b/src/modules/main-volume-policy/module-main-volume-policy.c 2016-04-18 11:01:31.497089360 +0200
-@@ -517,7 +517,7 @@
- { NULL },
- };
-
-- pa_config_parse(fn, f, config_items, NULL, u);
-+ pa_config_parse(fn, f, config_items, NULL, false, u);
- pa_xfree(fn);
- fn = NULL;
- fclose(f);