Remove old bbappend for pulseaudio 55/28955/2
authorKévin THIERRY <kevin.thierry@open.eurogiciel.org>
Fri, 17 Oct 2014 12:21:49 +0000 (14:21 +0200)
committerronan(Eurogiciel) Le Martret <ronan.lemartret@open.eurogiciel.org>
Mon, 20 Oct 2014 09:11:50 +0000 (02:11 -0700)
We now use our own source and recipe for pulseaudio and don't rely
anymore on the upstream recipe so there is no need to keep the old
bbappend and patches.

Change-Id: Id7e988f2c4fc577dc64e963146e9bd7b10648d4a
Signed-off-by: Kévin THIERRY <kevin.thierry@open.eurogiciel.org>
107 files changed:
recipes-multimedia/pulseaudio/pulseaudio_5.0.bbappend [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0001-volume-ramp-additions-to-the-low-level-infra.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0002-volume-ramp-add-volume-ramping-to-sink.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0003-volume-ramp-adding-volume-ramping-to-sink-input.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0004-build-sys-install-files-for-a-module-development.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0005-jack-detection-fix-for-wired-headset.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0006-make-pa_thread_mq_done-safe-for-subsequent-calls.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0007-node-manager-adding-external-node-manager-API.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0008-node-manager-adding-node-support-for-pactl.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0009-add-internal-corking-state-for-sink-input.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0010-bluetooth-Add-basic-support-for-HEADSET-profiles.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0011-bluetooth-Create-Handsfree-Audio-Agent-NULL-backend.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0012-bluetooth-Create-Handsfree-Audio-Agent-oFono-backend.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0013-bluetooth-Monitor-D-Bus-signals.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0014-bluetooth-Create-pa_bluetooth_dbus_send_and_add_to_p.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0015-bluetooth-Register-Unregister-Handsfree-Audio-Agent-.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0016-bluetooth-List-HandsfreeAudioCard-objects-from-oFono.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0017-bluetooth-Parse-HandsfreeAudioCard-properties.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0018-bluetooth-Implement-transport-acquire-for-hf_audio_a.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0019-bluetooth-Track-oFono-service.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0020-bluetooth-Handle-CardAdded-signal.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0021-bluetooth-Handle-CardRemoved-signal.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0022-bluetooth-Implement-org.ofono.HandsfreeAudioAgent.Ne.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0023-bluetooth-Fix-not-handle-fd-in-DEFER_SETUP-state.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0024-bluetooth-Suspend-sink-source-on-HFP-s-stream-HUP.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0025-bluetooth-Implement-transport-release-for-hf_audio_a.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0026-bluetooth-Fixes-HFP-audio-transfer-when-initiator.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0027-bluetooth-Set-off-profile-as-default-for-newly-creat.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0028-fix-ofono-and-pulseaudio-starting-order-assert.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0029-hfp-do-safe-strcmp-in-dbus-handler.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0030-add-parameter-to-define-key-used-in-stream-restore.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0031-increase-alsa-rewind-safeguard.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0032-fix-for-profile-change-prototype-in-bluez5-patch.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0033-changes-to-pa-simple-api-samsung.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0034-add-support-for-samsung-power-management-samsung.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0035-Add-preload-fileter-for-resample-samsung.patch.gz [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0036-Enhance-for-echo-cancel-samsung.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0037-add-support-for-dlog-samsung.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0038-add-policy-module-samsung.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0039-add-bluetooth-a2dp-aptx-codec-support-samsung.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0040-create-pa_ready-file-samsung.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0041-set-alsa-suspend-timeout-to-zero-samsung.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0042-cope-with-possible-infinite-waiting-in-startup-samsu.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0043-use-udev-only-for-usb-devices-samsung.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0044-fixes-and-improvements-to-makefile-and-configure-in-.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0045-fix-warning-in-gconf-helper.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0046-volume-ramp-add-client-api-support-for-volume-rampin.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0047-adjust-default-bluetooth-profile-to-off.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0048-Add-bt_profile_set-patch-which-fixed-bt-a2dp-hsp-pro.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0049-added-pulseaudio.service-file.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0050-.gitignore-Add-pulsecore-config.h.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0051-pactl-Fix-crash-with-older-servers.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0052-volume-Increase-PA_SW_VOLUME_SNPRINT_DB_MAX.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0053-sink-input-source-output-Fix-mute-saving.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0054-direction-Add-a-couple-of-direction-helper-functions.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0055-core-util-Add-pa_join.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0056-dynarray-Add-pa_dynarray_get_raw_array.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0057-dynarray-Add-PA_DYNARRAY_FOREACH.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0058-dynarray-Add-pa_dynarray_remove_last.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0059-dynarray-Add-pa_dynarray_remove_all.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0060-hashmap-Add-pa_hashmap_remove_and_free.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0061-device-port-Add-pa_device_port.active.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0062-sink-source-Assign-to-reference_volume-from-only-one.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0063-sink-input-source-output-Assign-to-volume-from-only-.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0064-sink-source-Return-early-from-set_mute.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0065-sink-input-source-output-Add-logging-to-set_mute.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0066-sink-source-Allow-calling-set_mute-during-initializa.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0067-echo-cancel-Remove-redundant-get_mute-callback.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0068-sink-source-Call-set_mute-from-mute_changed.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0069-sink-source-Assign-to-s-muted-from-only-one-place.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0070-sink-input-source-output-Remove-redundant-get_mute-f.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0071-solaris-tunnel-Remove-some-redundant-boolean-convers.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0072-sink-source-Add-hooks-for-volume-changes.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0073-sink-input-source-output-Add-hooks-for-volume-change.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0074-sink-source-Add-hooks-for-mute-changes.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0075-sink-input-source-output-Add-hooks-for-mute-changes.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0076-sink-Link-monitor-source-before-activating-port.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0077-context-extension-Add-the-pa_extension-class.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0078-volume-api-Add-libvolume-api.so.patch.gz [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0079-Add-module-volume-api-and-the-related-client-API.patch.gz [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0080-pactl-Add-support-for-the-new-volume-API.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0081-Add-module-audio-groups.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0082-Add-module-main-volume-policy.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0083-configuration-Add-default-IVI-audio-group-and-main-v.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0084-sink-source-Initialize-port-before-fixate-hook-fixes.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0085-configuration-pulseaudio-tizen-configuration-in-defa.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0086-pactl-Fix-crash-in-pactl-list.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0087-configuration-x-example-x-tizen-ivi-in-volume-config.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0088-device-creator-stream-creator-Add-a-couple-of-assert.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0089-main-volume-policy-Fix-a-memory-leak.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0090-audio-groups-fix-issues-found-by-static-analysis.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0091-core-util-Add-pa_append_to_home_dir.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0092-core-util-Add-pa_get_config_home_dir.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0093-core-util-Add-pa_append_to_config_home_dir.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0094-core-Create-the-config-home-directory-on-startup.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0095-alsa-Handle-unlinking-of-uninitialized-streams-grace.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0096-role-cork-Handle-unlinking-of-uninitialized-streams-.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0097-role-ducking-Handle-unlinking-of-uninitialized-strea.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0098-core-util-Add-pa_boolean_to_string.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0099-sink-input-source-output-Assign-to-reference_ratio-f.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0100-sink-input-source-output-Add-hooks-for-reference-rat.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0101-sink-input-source-output-Use-new_data.volume-only-fo.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0102-sink-input-source-output-Add-the-real-object-pointer.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/0103-audio-groups-main-volume-policy-volume-api-Various-f.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/change_libsystemd_to_libsystemd-login_in_configure.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_5.0/changes-to-pa-simple-api-samsung.patch [deleted file]
recipes-multimedia/pulseaudio/pulseaudio_git.bb_old [deleted file]

diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0.bbappend b/recipes-multimedia/pulseaudio/pulseaudio_5.0.bbappend
deleted file mode 100644 (file)
index 9258eb3..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-FILESEXTRAPATHS_prepend := "${THISDIR}/pulseaudio_5.0:"
-
-SRC_URI += "file://change_libsystemd_to_libsystemd-login_in_configure.patch"
-#SRC_URI += "file://changes-to-pa-simple-api-samsung.patch"
-
-B="${S}"
-
-SRC_URI += "file://0001-volume-ramp-additions-to-the-low-level-infra.patch"
-SRC_URI += "file://0002-volume-ramp-add-volume-ramping-to-sink.patch"
-SRC_URI += "file://0003-volume-ramp-adding-volume-ramping-to-sink-input.patch"
-SRC_URI += "file://0004-build-sys-install-files-for-a-module-development.patch"
-SRC_URI += "file://0005-jack-detection-fix-for-wired-headset.patch"
-SRC_URI += "file://0006-make-pa_thread_mq_done-safe-for-subsequent-calls.patch"
-SRC_URI += "file://0007-node-manager-adding-external-node-manager-API.patch"
-SRC_URI += "file://0008-node-manager-adding-node-support-for-pactl.patch"
-SRC_URI += "file://0009-add-internal-corking-state-for-sink-input.patch"
-SRC_URI += "file://0010-bluetooth-Add-basic-support-for-HEADSET-profiles.patch"
-SRC_URI += "file://0011-bluetooth-Create-Handsfree-Audio-Agent-NULL-backend.patch"
-SRC_URI += "file://0012-bluetooth-Create-Handsfree-Audio-Agent-oFono-backend.patch"
-SRC_URI += "file://0013-bluetooth-Monitor-D-Bus-signals.patch"
-SRC_URI += "file://0014-bluetooth-Create-pa_bluetooth_dbus_send_and_add_to_p.patch"
-SRC_URI += "file://0015-bluetooth-Register-Unregister-Handsfree-Audio-Agent-.patch"
-SRC_URI += "file://0016-bluetooth-List-HandsfreeAudioCard-objects-from-oFono.patch"
-SRC_URI += "file://0017-bluetooth-Parse-HandsfreeAudioCard-properties.patch"
-SRC_URI += "file://0018-bluetooth-Implement-transport-acquire-for-hf_audio_a.patch"
-SRC_URI += "file://0019-bluetooth-Track-oFono-service.patch"
-SRC_URI += "file://0020-bluetooth-Handle-CardAdded-signal.patch"
-SRC_URI += "file://0021-bluetooth-Handle-CardRemoved-signal.patch"
-SRC_URI += "file://0022-bluetooth-Implement-org.ofono.HandsfreeAudioAgent.Ne.patch"
-SRC_URI += "file://0023-bluetooth-Fix-not-handle-fd-in-DEFER_SETUP-state.patch"
-SRC_URI += "file://0024-bluetooth-Suspend-sink-source-on-HFP-s-stream-HUP.patch"
-SRC_URI += "file://0025-bluetooth-Implement-transport-release-for-hf_audio_a.patch"
-SRC_URI += "file://0026-bluetooth-Fixes-HFP-audio-transfer-when-initiator.patch"
-SRC_URI += "file://0027-bluetooth-Set-off-profile-as-default-for-newly-creat.patch"
-SRC_URI += "file://0028-fix-ofono-and-pulseaudio-starting-order-assert.patch"
-SRC_URI += "file://0029-hfp-do-safe-strcmp-in-dbus-handler.patch"
-SRC_URI += "file://0030-add-parameter-to-define-key-used-in-stream-restore.patch"
-SRC_URI += "file://0031-increase-alsa-rewind-safeguard.patch"
-SRC_URI += "file://0032-fix-for-profile-change-prototype-in-bluez5-patch.patch"
-SRC_URI += "file://0033-changes-to-pa-simple-api-samsung.patch"
-SRC_URI += "file://0034-add-support-for-samsung-power-management-samsung.patch"
-SRC_URI += "file://0035-Add-preload-fileter-for-resample-samsung.patch.gz"
-SRC_URI += "file://0036-Enhance-for-echo-cancel-samsung.patch"
-SRC_URI += "file://0037-add-support-for-dlog-samsung.patch"
-SRC_URI += "file://0038-add-policy-module-samsung.patch"
-SRC_URI += "file://0039-add-bluetooth-a2dp-aptx-codec-support-samsung.patch"
-SRC_URI += "file://0040-create-pa_ready-file-samsung.patch"
-SRC_URI += "file://0041-set-alsa-suspend-timeout-to-zero-samsung.patch"
-SRC_URI += "file://0042-cope-with-possible-infinite-waiting-in-startup-samsu.patch"
-SRC_URI += "file://0043-use-udev-only-for-usb-devices-samsung.patch"
-SRC_URI += "file://0044-fixes-and-improvements-to-makefile-and-configure-in-.patch"
-SRC_URI += "file://0045-fix-warning-in-gconf-helper.patch"
-SRC_URI += "file://0046-volume-ramp-add-client-api-support-for-volume-rampin.patch"
-SRC_URI += "file://0047-adjust-default-bluetooth-profile-to-off.patch"
-SRC_URI += "file://0048-Add-bt_profile_set-patch-which-fixed-bt-a2dp-hsp-pro.patch"
-SRC_URI += "file://0049-added-pulseaudio.service-file.patch"
-SRC_URI += "file://0050-.gitignore-Add-pulsecore-config.h.patch"
-SRC_URI += "file://0051-pactl-Fix-crash-with-older-servers.patch"
-SRC_URI += "file://0052-volume-Increase-PA_SW_VOLUME_SNPRINT_DB_MAX.patch"
-SRC_URI += "file://0053-sink-input-source-output-Fix-mute-saving.patch"
-SRC_URI += "file://0054-direction-Add-a-couple-of-direction-helper-functions.patch"
-SRC_URI += "file://0055-core-util-Add-pa_join.patch"
-SRC_URI += "file://0056-dynarray-Add-pa_dynarray_get_raw_array.patch"
-SRC_URI += "file://0057-dynarray-Add-PA_DYNARRAY_FOREACH.patch"
-SRC_URI += "file://0058-dynarray-Add-pa_dynarray_remove_last.patch"
-SRC_URI += "file://0059-dynarray-Add-pa_dynarray_remove_all.patch"
-SRC_URI += "file://0060-hashmap-Add-pa_hashmap_remove_and_free.patch"
-SRC_URI += "file://0061-device-port-Add-pa_device_port.active.patch"
-SRC_URI += "file://0062-sink-source-Assign-to-reference_volume-from-only-one.patch"
-SRC_URI += "file://0063-sink-input-source-output-Assign-to-volume-from-only-.patch"
-SRC_URI += "file://0064-sink-source-Return-early-from-set_mute.patch"
-SRC_URI += "file://0065-sink-input-source-output-Add-logging-to-set_mute.patch"
-SRC_URI += "file://0066-sink-source-Allow-calling-set_mute-during-initializa.patch"
-SRC_URI += "file://0067-echo-cancel-Remove-redundant-get_mute-callback.patch"
-SRC_URI += "file://0068-sink-source-Call-set_mute-from-mute_changed.patch"
-SRC_URI += "file://0069-sink-source-Assign-to-s-muted-from-only-one-place.patch"
-SRC_URI += "file://0070-sink-input-source-output-Remove-redundant-get_mute-f.patch"
-SRC_URI += "file://0071-solaris-tunnel-Remove-some-redundant-boolean-convers.patch"
-SRC_URI += "file://0072-sink-source-Add-hooks-for-volume-changes.patch"
-SRC_URI += "file://0073-sink-input-source-output-Add-hooks-for-volume-change.patch"
-SRC_URI += "file://0074-sink-source-Add-hooks-for-mute-changes.patch"
-SRC_URI += "file://0075-sink-input-source-output-Add-hooks-for-mute-changes.patch"
-SRC_URI += "file://0076-sink-Link-monitor-source-before-activating-port.patch"
-SRC_URI += "file://0077-context-extension-Add-the-pa_extension-class.patch"
-SRC_URI += "file://0078-volume-api-Add-libvolume-api.so.patch.gz"
-SRC_URI += "file://0079-Add-module-volume-api-and-the-related-client-API.patch.gz"
-SRC_URI += "file://0080-pactl-Add-support-for-the-new-volume-API.patch"
-SRC_URI += "file://0081-Add-module-audio-groups.patch"
-SRC_URI += "file://0082-Add-module-main-volume-policy.patch"
-SRC_URI += "file://0083-configuration-Add-default-IVI-audio-group-and-main-v.patch"
-SRC_URI += "file://0084-sink-source-Initialize-port-before-fixate-hook-fixes.patch"
-SRC_URI += "file://0085-configuration-pulseaudio-tizen-configuration-in-defa.patch"
-SRC_URI += "file://0086-pactl-Fix-crash-in-pactl-list.patch"
-SRC_URI += "file://0087-configuration-x-example-x-tizen-ivi-in-volume-config.patch"
-SRC_URI += "file://0088-device-creator-stream-creator-Add-a-couple-of-assert.patch"
-SRC_URI += "file://0089-main-volume-policy-Fix-a-memory-leak.patch"
-SRC_URI += "file://0090-audio-groups-fix-issues-found-by-static-analysis.patch"
-SRC_URI += "file://0091-core-util-Add-pa_append_to_home_dir.patch"
-SRC_URI += "file://0092-core-util-Add-pa_get_config_home_dir.patch"
-SRC_URI += "file://0093-core-util-Add-pa_append_to_config_home_dir.patch"
-SRC_URI += "file://0094-core-Create-the-config-home-directory-on-startup.patch"
-SRC_URI += "file://0095-alsa-Handle-unlinking-of-uninitialized-streams-grace.patch"
-SRC_URI += "file://0096-role-cork-Handle-unlinking-of-uninitialized-streams-.patch"
-SRC_URI += "file://0097-role-ducking-Handle-unlinking-of-uninitialized-strea.patch"
-SRC_URI += "file://0098-core-util-Add-pa_boolean_to_string.patch"
-SRC_URI += "file://0099-sink-input-source-output-Assign-to-reference_ratio-f.patch"
-SRC_URI += "file://0100-sink-input-source-output-Add-hooks-for-reference-rat.patch"
-SRC_URI += "file://0101-sink-input-source-output-Use-new_data.volume-only-fo.patch"
-SRC_URI += "file://0102-sink-input-source-output-Add-the-real-object-pointer.patch"
-SRC_URI += "file://0103-audio-groups-main-volume-policy-volume-api-Various-f.patch"
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0001-volume-ramp-additions-to-the-low-level-infra.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0001-volume-ramp-additions-to-the-low-level-infra.patch
deleted file mode 100644 (file)
index 8b2693c..0000000
+++ /dev/null
@@ -1,559 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@helsinki.fi>
-Date: Wed, 8 Aug 2012 11:14:37 +0300
-Subject: volume ramp: additions to the low level infra
-
-Change-Id: Ib2be01e0bea0856ebd0256066981fe34d05a4f86
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/map-file        |   4 +
- src/pulse/def.h     |  13 ++-
- src/pulse/volume.c  |  74 ++++++++++++-
- src/pulse/volume.h  |  33 ++++++
- src/pulsecore/mix.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/pulsecore/mix.h |  27 +++++
- 6 files changed, 459 insertions(+), 2 deletions(-)
-
-diff --git a/src/map-file b/src/map-file
-index fbad1a4..9903942 100644
---- a/src/map-file
-+++ b/src/map-file
-@@ -136,6 +136,10 @@ pa_cvolume_max_mask;
- pa_cvolume_merge;
- pa_cvolume_min;
- pa_cvolume_min_mask;
-+pa_cvolume_ramp_equal;
-+pa_cvolume_ramp_init;
-+pa_cvolume_ramp_set;
-+pa_cvolume_ramp_channel_ramp_set;
- pa_cvolume_remap;
- pa_cvolume_scale;
- pa_cvolume_scale_mask;
-diff --git a/src/pulse/def.h b/src/pulse/def.h
-index d6fa912..b7854a3 100644
---- a/src/pulse/def.h
-+++ b/src/pulse/def.h
-@@ -349,11 +349,15 @@ typedef enum pa_stream_flags {
-      * 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 */
-@@ -382,6 +386,7 @@ typedef enum pa_stream_flags {
- #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 */
-@@ -1049,6 +1054,12 @@ typedef enum pa_port_available {
- /** \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
-diff --git a/src/pulse/volume.c b/src/pulse/volume.c
-index 6927392..b140cee 100644
---- a/src/pulse/volume.c
-+++ b/src/pulse/volume.c
-@@ -447,7 +447,10 @@ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) {
-     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++)
-@@ -988,3 +991,72 @@ pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) {
-     return pa_cvolume_scale(v, m);
- }
-+
-+int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b) {
-+    int i;
-+    pa_assert(a);
-+    pa_assert(b);
-+
-+    if (PA_UNLIKELY(a == b))
-+        return 1;
-+
-+    if (a->channels != b->channels)
-+        return 0;
-+
-+    for (i = 0; i < a->channels; i++) {
-+        if (a->ramps[i].type != b->ramps[i].type ||
-+            a->ramps[i].length != b->ramps[i].length ||
-+            a->ramps[i].target != b->ramps[i].target)
-+            return 0;
-+    }
-+
-+    return 1;
-+}
-+
-+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;
-+}
-diff --git a/src/pulse/volume.h b/src/pulse/volume.h
-index 7806954..3ffb573 100644
---- a/src/pulse/volume.h
-+++ b/src/pulse/volume.h
-@@ -415,6 +415,39 @@ pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc);
-  * 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 pa_cvolume_ramp {
-+    uint8_t channels;
-+    pa_volume_ramp_t ramps[PA_CHANNELS_MAX];
-+} pa_cvolume_ramp;
-+
-+/** Return non-zero when *a == *b */
-+int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b);
-+
-+/** 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
-diff --git a/src/pulsecore/mix.c b/src/pulsecore/mix.c
-index 4b789a6..c1e0c18 100644
---- a/src/pulsecore/mix.c
-+++ b/src/pulsecore/mix.c
-@@ -721,3 +721,313 @@ void pa_volume_memchunk(
-     pa_memblock_release(c->memblock);
- }
-+
-+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, j, channels, remaining_channels;
-+    float temp;
-+
-+    if (dst->channels < src->channels) {
-+        channels = dst->channels;
-+        remaining_channels = 0;
-+    }
-+    else {
-+        channels = src->channels;
-+        remaining_channels = dst->channels;
-+    }
-+
-+    for (i = 0; i < 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;
-+    }
-+
-+    j = i;
-+
-+    for (i--; j < remaining_channels; j++) {
-+        dst->ramps[j].type = dst->ramps[i].type;
-+        dst->ramps[j].length = dst->ramps[i].length;
-+        dst->ramps[j].left = dst->ramps[i].left;
-+        dst->ramps[j].start = dst->ramps[i].start;
-+        dst->ramps[j].target = dst->ramps[i].target;
-+        dst->ramps[j].end = dst->ramps[i].end;
-+    }
-+
-+    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;
-+}
-diff --git a/src/pulsecore/mix.h b/src/pulsecore/mix.h
-index a4cde01..b1ec74f 100644
---- a/src/pulsecore/mix.h
-+++ b/src/pulsecore/mix.h
-@@ -61,4 +61,31 @@ void pa_volume_memchunk(
-     const pa_sample_spec *spec,
-     const pa_cvolume *volume);
-+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);
-+
- #endif
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0002-volume-ramp-add-volume-ramping-to-sink.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0002-volume-ramp-add-volume-ramping-to-sink.patch
deleted file mode 100644 (file)
index 4ea7c20..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@helsinki.fi>
-Date: Wed, 8 Aug 2012 11:14:39 +0300
-Subject: volume ramp: add volume ramping to sink
-
-Change-Id: I72bd64b4e4ad161ae0526a7e40d4bf9e843ae98c
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/sink.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++---
- src/pulsecore/sink.h |  9 +++++
- 2 files changed, 96 insertions(+), 5 deletions(-)
-
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index f4647b8..61656ab 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -333,6 +333,8 @@ pa_sink* pa_sink_new(
-             &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);
-@@ -356,6 +358,8 @@ pa_sink* pa_sink_new(
-     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);
-@@ -1189,6 +1193,7 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
-     } else if (n == 1) {
-         pa_cvolume volume;
-+        pa_cvolume target;
-         *result = info[0].chunk;
-         pa_memblock_ref(result->memblock);
-@@ -1205,12 +1210,25 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
-                                     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;
-+        pa_cvolume target_vol;
-+
-         result->memblock = pa_memblock_new(s->core->mempool, length);
-         ptr = pa_memblock_acquire(result->memblock);
-@@ -1219,6 +1237,16 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
-                                 &s->sample_spec,
-                                 &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(result, &s->sample_spec, &(s->thread_info.ramp));
-+                else {
-+                    pa_cvolume_ramp_get_targets(&s->thread_info.ramp, &target_vol);
-+                    pa_volume_memchunk(result, &s->sample_spec, &target_vol);
-+                }
-+        }
-+
-         pa_memblock_release(result->memblock);
-         result->index = 0;
-@@ -1279,6 +1307,7 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
-             pa_silence_memchunk(target, &s->sample_spec);
-         else {
-             pa_memchunk vchunk;
-+            pa_cvolume target_vol;
-             vchunk = info[0].chunk;
-             pa_memblock_ref(vchunk.memblock);
-@@ -1286,9 +1315,20 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
-             if (vchunk.length > length)
-                 vchunk.length = length;
--            if (!pa_cvolume_is_norm(&volume)) {
-+            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(&vchunk, 0);
--                pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
-+                if (pa_cvolume_ramp_active(&s->thread_info.ramp)) {
-+                    if (!pa_cvolume_is_norm(&volume))
-+                        pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
-+                    pa_volume_ramp_memchunk(&vchunk, &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_vol);
-+                        pa_sw_cvolume_multiply(&volume, &volume, &target_vol);
-+                    }
-+                    pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
-+                }
-             }
-             pa_memchunk_memcpy(target, &vchunk);
-@@ -1297,6 +1337,7 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
-     } else {
-         void *ptr;
-+        pa_cvolume target_vol;
-         ptr = pa_memblock_acquire(target->memblock);
-@@ -1306,6 +1347,15 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
-                                 &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);
-     }
-@@ -2085,6 +2135,32 @@ void pa_sink_set_volume(
-         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) {
-@@ -2737,13 +2813,19 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
-                 s->thread_info.soft_volume = s->soft_volume;
-                 pa_sink_request_rewind(s, (size_t) -1);
-             }
--
-             /* Fall through ... */
-         case PA_SINK_MESSAGE_SYNC_VOLUMES:
-             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;
-+            pa_sink_request_rewind(s, (size_t) -1);
-+            return 0;
-+
-         case PA_SINK_MESSAGE_GET_VOLUME:
-             if ((s->flags & PA_SINK_DEFERRED_VOLUME) && s->get_volume) {
-diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
-index c7cb5f8..576f34b 100644
---- a/src/pulsecore/sink.h
-+++ b/src/pulsecore/sink.h
-@@ -37,6 +37,7 @@ typedef struct pa_sink_volume_change pa_sink_volume_change;
- #include <pulsecore/core.h>
- #include <pulsecore/idxset.h>
- #include <pulsecore/memchunk.h>
-+#include <pulsecore/mix.h>
- #include <pulsecore/source.h>
- #include <pulsecore/module.h>
- #include <pulsecore/asyncmsgq.h>
-@@ -105,6 +106,9 @@ struct pa_sink {
-     pa_cvolume saved_volume;
-     bool saved_save_volume:1;
-+    /* for volume ramps */
-+    pa_cvolume_ramp_int ramp;
-+
-     pa_asyncmsgq *asyncmsgq;
-     pa_memchunk silence;
-@@ -288,6 +292,8 @@ struct pa_sink {
-         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;
-@@ -322,6 +328,7 @@ typedef enum pa_sink_message {
-     PA_SINK_MESSAGE_SET_PORT,
-     PA_SINK_MESSAGE_UPDATE_VOLUME_AND_MUTE,
-     PA_SINK_MESSAGE_SET_LATENCY_OFFSET,
-+    PA_SINK_MESSAGE_SET_VOLUME_RAMP,
-     PA_SINK_MESSAGE_MAX
- } pa_sink_message_t;
-@@ -443,6 +450,8 @@ bool pa_sink_get_mute(pa_sink *sink, bool force_refresh);
- bool pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p);
-+void pa_sink_set_volume_ramp(pa_sink *s, const pa_cvolume_ramp *ramp, bool send_msg, bool save);
-+
- int pa_sink_set_port(pa_sink *s, const char *name, bool save);
- void pa_sink_set_mixer_dirty(pa_sink *s, bool is_dirty);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0003-volume-ramp-adding-volume-ramping-to-sink-input.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0003-volume-ramp-adding-volume-ramping-to-sink-input.patch
deleted file mode 100644 (file)
index 9557dc8..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@helsinki.fi>
-Date: Wed, 8 Aug 2012 11:14:38 +0300
-Subject: volume ramp: adding volume ramping to sink-input
-
-Change-Id: I9376f531f3585c9ba5fb6d1b384589a8d123b292
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/sink-input.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
- src/pulsecore/sink-input.h | 12 +++++++++-
- 2 files changed, 70 insertions(+), 1 deletion(-)
-
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index f85b2c7..05ab25d 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -527,6 +527,11 @@ int pa_sink_input_new(
-     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->sink->sample_spec.channels);
-+    else
-+        pa_cvolume_ramp_int_init(&i->ramp, PA_VOLUME_NORM, data->sink->sample_spec.channels);
-+
-     i->thread_info.state = i->state;
-     i->thread_info.attached = false;
-     pa_atomic_store(&i->thread_info.drained, 1);
-@@ -543,6 +548,8 @@ int pa_sink_input_new(
-     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);
-@@ -924,6 +931,8 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink bytes */, pa
-         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);
-@@ -960,6 +969,16 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink bytes */, pa
-                     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;
-@@ -976,6 +995,16 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink bytes */, pa
-                         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(&rchunk, 0);
-+                        pa_volume_ramp_memchunk(&rchunk, &i->sink->sample_spec, &(i->thread_info.ramp));
-+                    } else if (pa_cvolume_ramp_target_active(&(i->thread_info.ramp))) {
-+                        pa_memchunk_make_writable(&rchunk, 0);
-+                        pa_cvolume_ramp_get_targets(&i->thread_info.ramp, &target);
-+                        pa_volume_memchunk(&rchunk, &i->sink->sample_spec, &target);
-+                    }
-+
-                     pa_memblockq_push_align(i->thread_info.render_memblockq, &rchunk);
-                     pa_memblock_unref(rchunk.memblock);
-                 }
-@@ -1351,6 +1380,29 @@ int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key) {
-     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);
-@@ -1968,6 +2020,13 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
-             }
-             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;
-+            pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
-+            return 0;
-+
-         case PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE:
-             if (i->thread_info.muted != i->muted) {
-                 i->thread_info.muted = i->muted;
-diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
-index da33717..3f74054 100644
---- a/src/pulsecore/sink-input.h
-+++ b/src/pulsecore/sink-input.h
-@@ -35,6 +35,7 @@ typedef struct pa_sink_input pa_sink_input;
- #include <pulsecore/client.h>
- #include <pulsecore/sink.h>
- #include <pulsecore/core.h>
-+#include <pulsecore/mix.h>
- typedef enum pa_sink_input_state {
-     PA_SINK_INPUT_INIT,         /*< The stream is not active yet, because pa_sink_input_put() has not been called yet */
-@@ -61,7 +62,8 @@ typedef enum pa_sink_input_flags {
-     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 {
-@@ -124,6 +126,9 @@ struct pa_sink_input {
-      * 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
-@@ -252,6 +257,8 @@ struct pa_sink_input {
-         pa_usec_t requested_sink_latency;
-         pa_hashmap *direct_outputs;
-+
-+        pa_cvolume_ramp_int ramp;
-     } thread_info;
-     void *userdata;
-@@ -268,6 +275,7 @@ enum {
-     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
- };
-@@ -377,6 +385,8 @@ pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, bool
- void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save);
- bool pa_sink_input_get_mute(pa_sink_input *i);
-+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/recipes-multimedia/pulseaudio/pulseaudio_5.0/0004-build-sys-install-files-for-a-module-development.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0004-build-sys-install-files-for-a-module-development.patch
deleted file mode 100644 (file)
index 8b43385..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@helsinki.fi>
-Date: Tue, 5 Jun 2012 11:36:13 +0300
-Subject: build-sys: install files for a module development.
-
-Change-Id: Ib68b292e1f6bc82bb5c148ef53acf51cc571406e
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- Makefile.am                   | 11 ++++++++++-
- configure.ac                  |  1 +
- pulseaudio-module-devel.pc.in | 12 ++++++++++++
- 3 files changed, 23 insertions(+), 1 deletion(-)
- create mode 100644 pulseaudio-module-devel.pc.in
-
-diff --git a/Makefile.am b/Makefile.am
-index b0b2553..a6a0b40 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -50,7 +50,13 @@ dist_vapi_DATA = \
-               vala/libpulse-mainloop-glib.deps vala/libpulse-mainloop-glib.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 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 += \
-@@ -89,6 +95,9 @@ dist-hook:
- check-daemon:
-       $(MAKE) -C src check-daemon
-+pulsecore-config.h: config.h
-+      cp $< $@
-+
- .PHONY: homepage distcleancheck doxygen
- # see git-version-gen
-diff --git a/configure.ac b/configure.ac
-index 4854711..4e9f97e 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1384,6 +1384,7 @@ man/default.pa.5.xml
- man/pulse-cli-syntax.5.xml
- man/start-pulseaudio-kde.1.xml
- man/start-pulseaudio-x11.1.xml
-+pulseaudio-module-devel.pc
- ])
- AC_CONFIG_FILES([src/esdcompat:src/daemon/esdcompat.in], [chmod +x src/esdcompat])
-diff --git a/pulseaudio-module-devel.pc.in b/pulseaudio-module-devel.pc.in
-new file mode 100644
-index 0000000..85aadbc
---- /dev/null
-+++ b/pulseaudio-module-devel.pc.in
-@@ -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/recipes-multimedia/pulseaudio/pulseaudio_5.0/0005-jack-detection-fix-for-wired-headset.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0005-jack-detection-fix-for-wired-headset.patch
deleted file mode 100644 (file)
index 002e4ec..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Sun, 10 Jun 2012 15:13:11 +0300
-Subject: jack detection fix for wired headset
-
-Change-Id: I53d465bf56adc2e3e5551b43d59ff99b63bc76cc
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/alsa/mixer/paths/analog-output-headphones.conf | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/modules/alsa/mixer/paths/analog-output-headphones.conf b/src/modules/alsa/mixer/paths/analog-output-headphones.conf
-index 89d794f..4771bc6 100644
---- a/src/modules/alsa/mixer/paths/analog-output-headphones.conf
-+++ b/src/modules/alsa/mixer/paths/analog-output-headphones.conf
-@@ -95,7 +95,7 @@ volume = off
- ; On some machines Front is actually a part of the Headphone path
- [Element Front]
--switch = mute
-+switch = off
- volume = zero
- [Element Rear]
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0006-make-pa_thread_mq_done-safe-for-subsequent-calls.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0006-make-pa_thread_mq_done-safe-for-subsequent-calls.patch
deleted file mode 100644 (file)
index bfbf3d9..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-From: Janos Kovacs <jankovac503@gmail.com>
-Date: Thu, 16 Aug 2012 03:47:48 +0300
-Subject: make pa_thread_mq_done() safe for subsequent calls
-
-Change-Id: I71ab9efa72c38a2200a56b7a4d30116767bc104f
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/thread-mq.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/src/pulsecore/thread-mq.c b/src/pulsecore/thread-mq.c
-index d34b22b..f3c5b6c 100644
---- a/src/pulsecore/thread-mq.c
-+++ b/src/pulsecore/thread-mq.c
-@@ -144,6 +144,14 @@ void pa_thread_mq_init(pa_thread_mq *q, pa_mainloop_api *mainloop, pa_rtpoll *rt
- void pa_thread_mq_done(pa_thread_mq *q) {
-     pa_assert(q);
-+    if (!q->main_mainloop && !q->inq && !q->outq &&
-+        !q->read_main_event && !q->write_main_event)
-+        return;
-+
-+    pa_assert(q->main_mainloop);
-+    pa_assert(q->inq && q->outq);
-+    pa_assert(q->read_main_event && q->write_main_event);
-+
-     /* Since we are called from main context we can be sure that the
-      * inq is empty. However, the outq might still contain messages
-      * for the main loop, which we need to dispatch (e.g. release
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0007-node-manager-adding-external-node-manager-API.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0007-node-manager-adding-external-node-manager-API.patch
deleted file mode 100644 (file)
index 5deba2b..0000000
+++ /dev/null
@@ -1,568 +0,0 @@
-From: Ismo Puustinen <ismo.puustinen@intel.com>
-Date: Wed, 28 May 2014 11:11:56 +0300
-Subject: node manager: adding external node manager API
-
-Change-Id: I4f220f05b9de513a7003b3cea761c3540fa74685
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/Makefile.am              |   4 +
- src/map-file                 |  11 ++
- src/pulse/context.c          |   5 +
- src/pulse/ext-node-manager.c | 348 +++++++++++++++++++++++++++++++++++++++++++
- src/pulse/ext-node-manager.h |  93 ++++++++++++
- src/pulse/internal.h         |   6 +
- 6 files changed, 467 insertions(+)
- create mode 100644 src/pulse/ext-node-manager.c
- create mode 100644 src/pulse/ext-node-manager.h
-
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 857fda3..e1808e6 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -753,6 +753,8 @@ pulseinclude_HEADERS = \
-               pulse/ext-device-manager.h \
-               pulse/ext-device-restore.h \
-               pulse/ext-stream-restore.h \
-+              pulse/ext-echo-cancel.h \
-+              pulse/ext-node-manager.h \
-               pulse/format.h \
-               pulse/gccmacro.h \
-               pulse/introspect.h \
-@@ -798,6 +800,8 @@ libpulse_la_SOURCES = \
-               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-echo-cancel.c pulse/ext-echo-cancel.h \
-+              pulse/ext-node-manager.c pulse/ext-node-manager.h \
-               pulse/format.c pulse/format.h \
-               pulse/gccmacro.h \
-               pulse/internal.h \
-diff --git a/src/map-file b/src/map-file
-index 9903942..7dbcd00 100644
---- a/src/map-file
-+++ b/src/map-file
-@@ -171,6 +171,17 @@ pa_ext_stream_restore_set_subscribe_cb;
- pa_ext_stream_restore_subscribe;
- pa_ext_stream_restore_test;
- pa_ext_stream_restore_write;
-+pa_ext_policy_test;
-+pa_ext_policy_set_mono;
-+pa_ext_policy_set_balance;
-+pa_ext_echo_cancel_set_volume;
-+pa_ext_echo_cancel_set_device;
-+pa_ext_node_manager_test;
-+pa_ext_node_manager_read_nodes;
-+pa_ext_node_manager_connect_nodes;
-+pa_ext_node_manager_disconnect_nodes;
-+pa_ext_node_manager_subscribe;
-+pa_ext_node_manager_set_subscribe_cb;
- pa_format_info_copy;
- pa_format_info_free;
- pa_format_info_from_string;
-diff --git a/src/pulse/context.c b/src/pulse/context.c
-index b78df27..b8688f2 100644
---- a/src/pulse/context.c
-+++ b/src/pulse/context.c
-@@ -122,6 +122,9 @@ static void reset_callbacks(pa_context *c) {
-     c->ext_stream_restore.callback = NULL;
-     c->ext_stream_restore.userdata = NULL;
-+
-+    c->ext_node_manager.callback = NULL;
-+    c->ext_node_manager.userdata = NULL;
- }
- pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
-@@ -1361,6 +1364,8 @@ void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_t
-         pa_ext_device_restore_command(c, tag, t);
-     else if (pa_streq(name, "module-stream-restore"))
-         pa_ext_stream_restore_command(c, tag, t);
-+    else if (pa_streq(name, "module-node-manager"))
-+        pa_ext_node_manager_command(c, tag, t);
-     else
-         pa_log(_("Received message for unknown extension '%s'"), name);
-diff --git a/src/pulse/ext-node-manager.c b/src/pulse/ext-node-manager.c
-new file mode 100644
-index 0000000..5cb3feb
---- /dev/null
-+++ b/src/pulse/ext-node-manager.c
-@@ -0,0 +1,348 @@
-+/***
-+  This file is part of PulseAudio.
-+
-+  Copyright 2012 Jaska Uimonen
-+  Copyright 2012 Janos Kovacs
-+
-+  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 <pulse/context.h>
-+#include <pulse/xmalloc.h>
-+#include <pulse/fork-detect.h>
-+#include <pulse/operation.h>
-+
-+#include <pulsecore/macro.h>
-+#include <pulsecore/pstream-util.h>
-+
-+#include "internal.h"
-+#include "ext-node-manager.h"
-+
-+enum {
-+    SUBCOMMAND_TEST,
-+    SUBCOMMAND_READ,
-+    SUBCOMMAND_CONNECT,
-+    SUBCOMMAND_DISCONNECT,
-+    SUBCOMMAND_SUBSCRIBE,
-+    SUBCOMMAND_EVENT
-+};
-+
-+static void ext_node_manager_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-+    pa_operation *o = userdata;
-+    uint32_t version = PA_INVALID_INDEX;
-+
-+    pa_assert(pd);
-+    pa_assert(o);
-+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
-+
-+    if (!o->context)
-+        goto finish;
-+
-+    if (command != PA_COMMAND_REPLY) {
-+        if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
-+            goto finish;
-+
-+    } else if (pa_tagstruct_getu32(t, &version) < 0 ||
-+               !pa_tagstruct_eof(t)) {
-+
-+        pa_context_fail(o->context, PA_ERR_PROTOCOL);
-+        goto finish;
-+    }
-+
-+    if (o->callback) {
-+        pa_ext_node_manager_test_cb_t cb = (pa_ext_node_manager_test_cb_t) o->callback;
-+        cb(o->context, version, o->userdata);
-+    }
-+
-+finish:
-+    pa_operation_done(o);
-+    pa_operation_unref(o);
-+}
-+
-+pa_operation *pa_ext_node_manager_test(
-+        pa_context *c,
-+        pa_ext_node_manager_test_cb_t cb,
-+        void *userdata) {
-+
-+    uint32_t tag;
-+    pa_operation *o;
-+    pa_tagstruct *t;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
-+
-+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+    t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
-+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
-+    pa_tagstruct_puts(t, "module-murphy-ivi");
-+    pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
-+    pa_pstream_send_tagstruct(c->pstream, t);
-+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_node_manager_test_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+    return o;
-+}
-+
-+static void ext_node_manager_read_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-+    pa_operation *o = userdata;
-+    pa_ext_node_manager_info i;
-+
-+    pa_assert(pd);
-+    pa_assert(o);
-+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
-+
-+    if (!o->context)
-+        goto finish;
-+
-+    if (command != PA_COMMAND_REPLY) {
-+        if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
-+            goto finish;
-+    } else {
-+
-+        while (!pa_tagstruct_eof(t)) {
-+
-+            memset(&i, 0, sizeof(i));
-+
-+          i.props = pa_proplist_new();
-+
-+            if (pa_tagstruct_gets(t, &i.name) < 0 ||
-+                pa_tagstruct_get_proplist(t, i.props) < 0) {
-+
-+                pa_context_fail(o->context, PA_ERR_PROTOCOL);
-+                goto finish;
-+            }
-+
-+            if (o->callback) {
-+                pa_ext_node_manager_read_cb_t cb = (pa_ext_node_manager_read_cb_t) o->callback;
-+                cb(o->context, &i, 0, o->userdata);
-+            }
-+
-+          pa_proplist_free(i.props);
-+        }
-+
-+      /* let's send end marker */
-+      if (o->callback) {
-+                pa_ext_node_manager_read_cb_t cb = (pa_ext_node_manager_read_cb_t) o->callback;
-+                cb(o->context, &i, 1, o->userdata);
-+            }
-+    }
-+
-+finish:
-+    pa_operation_done(o);
-+    pa_operation_unref(o);
-+}
-+
-+pa_operation *pa_ext_node_manager_read_nodes(
-+        pa_context *c,
-+        pa_ext_node_manager_read_cb_t cb,
-+        void *userdata) {
-+
-+    uint32_t tag;
-+    pa_operation *o;
-+    pa_tagstruct *t;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
-+
-+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+    t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
-+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
-+    pa_tagstruct_puts(t, "module-murphy-ivi");
-+    pa_tagstruct_putu32(t, SUBCOMMAND_READ);
-+    pa_pstream_send_tagstruct(c->pstream, t);
-+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_node_manager_read_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+    return o;
-+}
-+
-+static void ext_node_manager_connect_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-+    pa_operation *o = userdata;
-+    uint32_t connection = PA_INVALID_INDEX;
-+
-+    pa_assert(pd);
-+    pa_assert(o);
-+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
-+
-+    if (!o->context)
-+        goto finish;
-+
-+    if (command != PA_COMMAND_REPLY) {
-+        if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
-+            goto finish;
-+
-+    } else if (pa_tagstruct_getu32(t, &connection) < 0 ||
-+               !pa_tagstruct_eof(t)) {
-+
-+        pa_context_fail(o->context, PA_ERR_PROTOCOL);
-+        goto finish;
-+    }
-+
-+    if (o->callback) {
-+        pa_ext_node_manager_connect_cb_t cb = (pa_ext_node_manager_connect_cb_t) o->callback;
-+        cb(o->context, connection, o->userdata);
-+    }
-+
-+finish:
-+    pa_operation_done(o);
-+    pa_operation_unref(o);
-+}
-+
-+pa_operation *pa_ext_node_manager_connect_nodes(
-+        pa_context *c,
-+        uint32_t source_node_id,
-+        uint32_t sink_node_id,
-+        pa_ext_node_manager_connect_cb_t cb,
-+        void *userdata) {
-+
-+    uint32_t tag;
-+    pa_operation *o = NULL;
-+    pa_tagstruct *t = NULL;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
-+
-+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+    t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
-+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
-+    pa_tagstruct_puts(t, "module-murphy-ivi");
-+    pa_tagstruct_putu32(t, SUBCOMMAND_CONNECT);
-+
-+    pa_tagstruct_putu32(t, source_node_id);
-+    pa_tagstruct_putu32(t, sink_node_id);
-+
-+    pa_pstream_send_tagstruct(c->pstream, t);
-+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_node_manager_connect_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+    return o;
-+}
-+
-+pa_operation *pa_ext_node_manager_disconnect_nodes(
-+        pa_context *c,
-+      uint32_t conn_id,
-+        pa_context_success_cb_t cb,
-+        void *userdata) {
-+
-+    uint32_t tag;
-+    pa_operation *o = NULL;
-+    pa_tagstruct *t = NULL;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
-+
-+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+    t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
-+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
-+    pa_tagstruct_puts(t, "module-murphy-ivi");
-+    pa_tagstruct_putu32(t, SUBCOMMAND_DISCONNECT);
-+
-+    pa_tagstruct_putu32(t, conn_id);
-+
-+    pa_pstream_send_tagstruct(c->pstream, t);
-+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+    return o;
-+}
-+
-+pa_operation *pa_ext_node_manager_subscribe(
-+        pa_context *c,
-+        int enable,
-+        pa_context_success_cb_t cb,
-+        void *userdata) {
-+
-+    uint32_t tag;
-+    pa_operation *o;
-+    pa_tagstruct *t;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
-+
-+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+    t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
-+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
-+    pa_tagstruct_puts(t, "module-murphy-ivi");
-+    pa_tagstruct_putu32(t, SUBCOMMAND_SUBSCRIBE);
-+    pa_tagstruct_put_boolean(t, enable);
-+    pa_pstream_send_tagstruct(c->pstream, t);
-+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+    return o;
-+}
-+
-+void pa_ext_node_manager_set_subscribe_cb(
-+        pa_context *c,
-+        pa_ext_node_manager_subscribe_cb_t cb,
-+        void *userdata) {
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+
-+    if (pa_detect_fork())
-+        return;
-+
-+    c->ext_node_manager.callback = cb;
-+    c->ext_node_manager.userdata = userdata;
-+}
-+
-+void pa_ext_node_manager_command(pa_context *c, uint32_t tag, pa_tagstruct *t) {
-+    uint32_t subcommand;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+    pa_assert(t);
-+
-+    if (pa_tagstruct_getu32(t, &subcommand) < 0 ||
-+        !pa_tagstruct_eof(t)) {
-+
-+        pa_context_fail(c, PA_ERR_PROTOCOL);
-+        return;
-+    }
-+
-+    if (subcommand != SUBCOMMAND_EVENT) {
-+        pa_context_fail(c, PA_ERR_PROTOCOL);
-+        return;
-+    }
-+
-+    if (c->ext_node_manager.callback)
-+        c->ext_node_manager.callback(c, c->ext_node_manager.userdata);
-+}
-diff --git a/src/pulse/ext-node-manager.h b/src/pulse/ext-node-manager.h
-new file mode 100644
-index 0000000..57b9f01
---- /dev/null
-+++ b/src/pulse/ext-node-manager.h
-@@ -0,0 +1,93 @@
-+#ifndef foopulseextnodemanagerhfoo
-+#define foopulseextnodemanagerhfoo
-+
-+/***
-+  This file is part of PulseAudio.
-+
-+  Copyright 2012 Jaska Uimonen
-+  Copyright 2012 Janos Kovacs
-+
-+  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/version.h>
-+
-+PA_C_DECL_BEGIN
-+
-+typedef struct pa_ext_node_manager_info {
-+    const char *name;
-+    pa_proplist *props;
-+} pa_ext_node_manager_info;
-+
-+typedef void (*pa_ext_node_manager_test_cb_t)(
-+        pa_context *c,
-+        uint32_t version,
-+        void *userdata);
-+
-+pa_operation *pa_ext_node_manager_test(
-+        pa_context *c,
-+        pa_ext_node_manager_test_cb_t cb,
-+        void *userdata);
-+
-+typedef void (*pa_ext_node_manager_read_cb_t)(
-+        pa_context *c,
-+        const pa_ext_node_manager_info *info,
-+        int eol,
-+        void *userdata);
-+
-+pa_operation *pa_ext_node_manager_read_nodes(
-+        pa_context *c,
-+        pa_ext_node_manager_read_cb_t cb,
-+        void *userdata);
-+
-+typedef void (*pa_ext_node_manager_connect_cb_t)(
-+        pa_context *c,
-+        uint32_t connection,
-+        void *userdata);
-+
-+pa_operation *pa_ext_node_manager_connect_nodes(
-+        pa_context *c,
-+        uint32_t src,
-+        uint32_t dst,
-+        pa_ext_node_manager_connect_cb_t cb,
-+        void *userdata);
-+
-+pa_operation *pa_ext_node_manager_disconnect_nodes(
-+        pa_context *c,
-+        uint32_t conn,
-+        pa_context_success_cb_t cb,
-+        void *userdata);
-+
-+pa_operation *pa_ext_node_manager_subscribe(
-+        pa_context *c,
-+        int enable,
-+        pa_context_success_cb_t cb,
-+        void *userdata);
-+
-+typedef void (*pa_ext_node_manager_subscribe_cb_t)(
-+        pa_context *c,
-+        void *userdata);
-+
-+void pa_ext_node_manager_set_subscribe_cb(
-+        pa_context *c,
-+        pa_ext_node_manager_subscribe_cb_t cb,
-+        void *userdata);
-+
-+PA_C_DECL_END
-+
-+#endif
-diff --git a/src/pulse/internal.h b/src/pulse/internal.h
-index c5084d5..61095d0 100644
---- a/src/pulse/internal.h
-+++ b/src/pulse/internal.h
-@@ -31,6 +31,7 @@
- #include <pulse/ext-device-manager.h>
- #include <pulse/ext-device-restore.h>
- #include <pulse/ext-stream-restore.h>
-+#include <pulse/ext-node-manager.h>
- #include <pulsecore/socket-client.h>
- #include <pulsecore/pstream.h>
-@@ -115,6 +116,10 @@ struct pa_context {
-         pa_ext_stream_restore_subscribe_cb_t callback;
-         void *userdata;
-     } ext_stream_restore;
-+    struct {
-+        pa_ext_node_manager_subscribe_cb_t callback;
-+        void *userdata;
-+    } ext_node_manager;
- };
- #define PA_MAX_WRITE_INDEX_CORRECTIONS 32
-@@ -303,6 +308,7 @@ pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *ta
- void pa_ext_device_manager_command(pa_context *c, uint32_t tag, pa_tagstruct *t);
- void pa_ext_device_restore_command(pa_context *c, uint32_t tag, pa_tagstruct *t);
- void pa_ext_stream_restore_command(pa_context *c, uint32_t tag, pa_tagstruct *t);
-+void pa_ext_node_manager_command(pa_context *c, uint32_t tag, pa_tagstruct *t);
- bool pa_mainloop_is_our_api(pa_mainloop_api*m);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0008-node-manager-adding-node-support-for-pactl.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0008-node-manager-adding-node-support-for-pactl.patch
deleted file mode 100644 (file)
index 64cc9c3..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Wed, 5 Dec 2012 09:53:12 +0200
-Subject: node-manager: adding node support for pactl
-
-Change-Id: Id6badeba2181ef4afa9842307e4c6c60f72c472f
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/utils/pactl.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
- 1 file changed, 72 insertions(+), 3 deletions(-)
-
-diff --git a/src/utils/pactl.c b/src/utils/pactl.c
-index 40e6689..1d8faa4 100644
---- a/src/utils/pactl.c
-+++ b/src/utils/pactl.c
-@@ -38,6 +38,7 @@
- #include <pulse/pulseaudio.h>
- #include <pulse/ext-device-restore.h>
-+#include <pulse/ext-node-manager.h>
- #include <pulsecore/i18n.h>
- #include <pulsecore/macro.h>
-@@ -97,6 +98,10 @@ static int actions = 1;
- static bool nl = false;
-+static uint32_t src_node_id;
-+static uint32_t dst_node_id;
-+static uint32_t conn_id;
-+
- static enum {
-     NONE,
-     EXIT,
-@@ -127,7 +132,9 @@ static enum {
-     SET_SOURCE_OUTPUT_MUTE,
-     SET_SINK_FORMATS,
-     SET_PORT_LATENCY_OFFSET,
--    SUBSCRIBE
-+    SUBSCRIBE,
-+    NODE_CONNECT,
-+    NODE_DISCONNECT
- } action = NONE;
- static void quit(int ret) {
-@@ -1007,6 +1014,30 @@ static void source_output_toggle_mute_callback(pa_context *c, const pa_source_ou
-     pa_operation_unref(pa_context_set_source_output_mute(c, o->index, !o->mute, simple_callback, NULL));
- }
-+static void node_list_callback(pa_context *c,
-+                             const pa_ext_node_manager_info *info,
-+                             int eol,
-+                             void *userdata) {
-+
-+    if (!eol) {
-+      const char *node_id = pa_proplist_gets(info->props, "index");
-+      if (node_id != NULL) {
-+          printf("Node #%s (%s)\n", node_id, info->name);
-+          printf("%s\n", pa_proplist_to_string(info->props));
-+      }
-+    } else
-+      complete_action();
-+}
-+
-+static void node_connect_callback(pa_context *c,
-+                          uint32_t conne_id,
-+                          void *userdata) {
-+
-+    printf("New connection id: %d\n", conne_id);
-+
-+    complete_action();
-+}
-+
- /* PA_MAX_FORMATS is defined in internal.h so we just define a sane value here */
- #define MAX_FORMATS 256
-@@ -1212,6 +1243,8 @@ static void context_state_callback(pa_context *c, void *userdata) {
-                             pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
-                         else if (pa_streq(list_type, "cards"))
-                             pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
-+                      else if (pa_streq(list_type, "nodes"))
-+                          pa_operation_unref(pa_ext_node_manager_read_nodes(c, node_list_callback, NULL));
-                         else
-                             pa_assert_not_reached();
-                     } else {
-@@ -1373,6 +1406,18 @@ static void context_state_callback(pa_context *c, void *userdata) {
-                                               NULL,
-                                               NULL));
-                     break;
-+              case NODE_CONNECT:
-+                  pa_operation_unref(pa_ext_node_manager_connect_nodes(c,
-+                                                                       src_node_id,
-+                                                                       dst_node_id,
-+                                                                       node_connect_callback,
-+                                                                       NULL));
-+                  break;
-+              case NODE_DISCONNECT:
-+                  pa_operation_unref(pa_ext_node_manager_disconnect_nodes(c, conn_id,
-+                                                                      simple_callback,
-+                                                                      NULL));
-+                  break;
-                 default:
-                     pa_assert_not_reached();
-@@ -1494,6 +1539,9 @@ static void help(const char *argv0) {
-     printf("%s %s %s\n",    argv0, _("[options]"), "subscribe");
-     printf(_("\nThe special names @DEFAULT_SINK@, @DEFAULT_SOURCE@ and @DEFAULT_MONITOR@\n"
-              "can be used to specify the default sink, source and monitor.\n"));
-+    printf("%s %s %s\n",    argv0, _("[options]"), "node-list ");
-+    printf("%s %s %s %s %s\n", argv0, _("[options]"), "node-connect ", _("#N"), _("#N"));
-+    printf("%s %s %s %s\n", argv0, _("[options]"), "node-disconnect ", _("#N"));
-     printf(_("\n"
-              "  -h, --help                            Show this help\n"
-@@ -1590,7 +1638,7 @@ int main(int argc, char *argv[]) {
-                 if (pa_streq(argv[i], "modules") || pa_streq(argv[i], "clients") ||
-                     pa_streq(argv[i], "sinks")   || pa_streq(argv[i], "sink-inputs") ||
-                     pa_streq(argv[i], "sources") || pa_streq(argv[i], "source-outputs") ||
--                    pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards")) {
-+                    pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards") || pa_streq(argv[i], "nodes")) {
-                     list_type = pa_xstrdup(argv[i]);
-                 } else if (pa_streq(argv[i], "short")) {
-                     short_list_format = true;
-@@ -1960,7 +2008,28 @@ int main(int argc, char *argv[]) {
-                 goto quit;
-             }
--        } else if (pa_streq(argv[optind], "help")) {
-+        } else if (pa_streq(argv[optind], "node-connect")) {
-+          action = NODE_CONNECT;
-+
-+          if (argc != optind+3) {
-+              pa_log(_("You have to specify a source and destination node indexes"));
-+              goto quit;
-+          }
-+
-+          src_node_id = (uint32_t) atoi(argv[optind+1]);
-+          dst_node_id = (uint32_t) atoi(argv[optind+2]);
-+
-+      } else if (pa_streq(argv[optind], "node-disconnect")) {
-+          action = NODE_DISCONNECT;
-+
-+          if (argc != optind+2) {
-+              pa_log(_("You have to specify a connection id"));
-+              goto quit;
-+          }
-+
-+          conn_id = (uint32_t) atoi(argv[optind+1]);
-+
-+      } else if (pa_streq(argv[optind], "help")) {
-             help(bn);
-             ret = 0;
-             goto quit;
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0009-add-internal-corking-state-for-sink-input.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0009-add-internal-corking-state-for-sink-input.patch
deleted file mode 100644 (file)
index 3ff665d..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Thu, 7 Mar 2013 13:41:44 +0200
-Subject: add internal corking state for sink-input
-
-Change-Id: Iaa7ef16c798e06c0fdf11097690c6cf49215773d
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/sink-input.c | 30 +++++++++++++++++++++++++++++-
- src/pulsecore/sink-input.h |  4 ++++
- 2 files changed, 33 insertions(+), 1 deletion(-)
-
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index 05ab25d..dff6324 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -788,6 +788,9 @@ void pa_sink_input_put(pa_sink_input *i) {
-     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);
-@@ -1506,13 +1509,38 @@ void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_p
-     }
- }
-+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 */
-diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
-index 3f74054..deea348 100644
---- a/src/pulsecore/sink-input.h
-+++ b/src/pulsecore/sink-input.h
-@@ -129,6 +129,9 @@ struct pa_sink_input {
-     /* 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
-@@ -360,6 +363,7 @@ implementing the "zero latency" write-through functionality. */
- 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/recipes-multimedia/pulseaudio/pulseaudio_5.0/0010-bluetooth-Add-basic-support-for-HEADSET-profiles.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0010-bluetooth-Add-basic-support-for-HEADSET-profiles.patch
deleted file mode 100644 (file)
index 3249f6f..0000000
+++ /dev/null
@@ -1,634 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Wed, 10 Jul 2013 09:45:01 -0300
-Subject: bluetooth: Add basic support for HEADSET profiles
-
-This commit adds basic support for devices implementing HSP Headset
-Unit, HSP Audio Gateway, HFP Handsfree Unit, HFP Audio Gateway to the
-BlueZ 5 bluetooth audio devices driver module (module-bluez5-device).
-
-Change-Id: I6be5bcf310a327012f382d408a70e7fdc65caab1
----
- src/modules/bluetooth/bluez5-util.c          |   4 +
- src/modules/bluetooth/bluez5-util.h          |   6 +
- src/modules/bluetooth/module-bluez5-device.c | 443 ++++++++++++++++++++-------
- 3 files changed, 345 insertions(+), 108 deletions(-)
-
-diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c
-index 7eecc18..ae219ea 100644
---- a/src/modules/bluetooth/bluez5-util.c
-+++ b/src/modules/bluetooth/bluez5-util.c
-@@ -1093,6 +1093,10 @@ const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile) {
-             return "a2dp_sink";
-         case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
-             return "a2dp_source";
-+        case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
-+            return "hsp";
-+        case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
-+            return "hfgw";
-         case PA_BLUETOOTH_PROFILE_OFF:
-             return "off";
-     }
-diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h
-index bbc5b71..841c3c6 100644
---- a/src/modules/bluetooth/bluez5-util.h
-+++ b/src/modules/bluetooth/bluez5-util.h
-@@ -26,6 +26,10 @@
- #define PA_BLUETOOTH_UUID_A2DP_SOURCE "0000110a-0000-1000-8000-00805f9b34fb"
- #define PA_BLUETOOTH_UUID_A2DP_SINK   "0000110b-0000-1000-8000-00805f9b34fb"
-+#define PA_BLUETOOTH_UUID_HSP_HS      "00001108-0000-1000-8000-00805f9b34fb"
-+#define PA_BLUETOOTH_UUID_HSP_AG      "00001112-0000-1000-8000-00805f9b34fb"
-+#define PA_BLUETOOTH_UUID_HFP_HF      "0000111e-0000-1000-8000-00805f9b34fb"
-+#define PA_BLUETOOTH_UUID_HFP_AG      "0000111f-0000-1000-8000-00805f9b34fb"
- typedef struct pa_bluetooth_transport pa_bluetooth_transport;
- typedef struct pa_bluetooth_device pa_bluetooth_device;
-@@ -41,6 +45,8 @@ typedef enum pa_bluetooth_hook {
- typedef enum profile {
-     PA_BLUETOOTH_PROFILE_A2DP_SINK,
-     PA_BLUETOOTH_PROFILE_A2DP_SOURCE,
-+    PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT,
-+    PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY,
-     PA_BLUETOOTH_PROFILE_OFF
- } pa_bluetooth_profile_t;
- #define PA_BLUETOOTH_PROFILE_COUNT PA_BLUETOOTH_PROFILE_OFF
-diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
-index 287e763..b511b92 100644
---- a/src/modules/bluetooth/module-bluez5-device.c
-+++ b/src/modules/bluetooth/module-bluez5-device.c
-@@ -33,6 +33,7 @@
- #include <pulse/timeval.h>
- #include <pulsecore/core-error.h>
-+#include <pulsecore/core-rtclock.h>
- #include <pulsecore/core-util.h>
- #include <pulsecore/i18n.h>
- #include <pulsecore/module.h>
-@@ -59,7 +60,9 @@ PA_MODULE_USAGE("path=<device object path>");
- #define MAX_PLAYBACK_CATCH_UP_USEC (100 * PA_USEC_PER_MSEC)
- #define FIXED_LATENCY_PLAYBACK_A2DP (25 * PA_USEC_PER_MSEC)
-+#define FIXED_LATENCY_PLAYBACK_SCO (125 * PA_USEC_PER_MSEC)
- #define FIXED_LATENCY_RECORD_A2DP   (25 * PA_USEC_PER_MSEC)
-+#define FIXED_LATENCY_RECORD_SCO    (25 * PA_USEC_PER_MSEC)
- #define BITPOOL_DEC_LIMIT 32
- #define BITPOOL_DEC_STEP 5
-@@ -235,6 +238,167 @@ static void connect_ports(struct userdata *u, void *new_data, pa_direction_t dir
- }
- /* Run from IO thread */
-+static int sco_process_render(struct userdata *u) {
-+    int ret = 0;
-+
-+    pa_assert(u);
-+    pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY);
-+    pa_assert(u->sink);
-+
-+    /* First, render some data */
-+    if (!u->write_memchunk.memblock)
-+        pa_sink_render_full(u->sink, u->write_block_size, &u->write_memchunk);
-+
-+    pa_assert(u->write_memchunk.length == u->write_block_size);
-+
-+    for (;;) {
-+        ssize_t l;
-+        const void *p;
-+
-+        /* Now write that data to the socket. The socket is of type
-+         * SEQPACKET, and we generated the data of the MTU size, so this
-+         * should just work. */
-+
-+        p = (const uint8_t *) pa_memblock_acquire_chunk(&u->write_memchunk);
-+        l = pa_write(u->stream_fd, p, u->write_memchunk.length, &u->stream_write_type);
-+        pa_memblock_release(u->write_memchunk.memblock);
-+
-+        pa_assert(l != 0);
-+
-+        if (l < 0) {
-+
-+            if (errno == EINTR)
-+                /* Retry right away if we got interrupted */
-+                continue;
-+
-+            else if (errno == EAGAIN)
-+                /* Hmm, apparently the socket was not writable, give up for now */
-+                break;
-+
-+            pa_log_error("Failed to write data to SCO socket: %s", pa_cstrerror(errno));
-+            ret = -1;
-+            break;
-+        }
-+
-+        pa_assert((size_t) l <= u->write_memchunk.length);
-+
-+        if ((size_t) l != u->write_memchunk.length) {
-+            pa_log_error("Wrote memory block to socket only partially! %llu written, wanted to write %llu.",
-+                        (unsigned long long) l,
-+                        (unsigned long long) u->write_memchunk.length);
-+            ret = -1;
-+            break;
-+        }
-+
-+        u->write_index += (uint64_t) u->write_memchunk.length;
-+        pa_memblock_unref(u->write_memchunk.memblock);
-+        pa_memchunk_reset(&u->write_memchunk);
-+
-+        ret = 1;
-+        break;
-+    }
-+
-+    return ret;
-+}
-+
-+/* Run from IO thread */
-+static int sco_process_push(struct userdata *u) {
-+    int ret = 0;
-+    pa_memchunk memchunk;
-+
-+    pa_assert(u);
-+    pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY);
-+    pa_assert(u->source);
-+    pa_assert(u->read_smoother);
-+
-+    memchunk.memblock = pa_memblock_new(u->core->mempool, u->read_block_size);
-+    memchunk.index = memchunk.length = 0;
-+
-+    for (;;) {
-+        ssize_t l;
-+        void *p;
-+        struct msghdr m;
-+        struct cmsghdr *cm;
-+        uint8_t aux[1024];
-+        struct iovec iov;
-+        bool found_tstamp = false;
-+        pa_usec_t tstamp;
-+
-+        memset(&m, 0, sizeof(m));
-+        memset(&aux, 0, sizeof(aux));
-+        memset(&iov, 0, sizeof(iov));
-+
-+        m.msg_iov = &iov;
-+        m.msg_iovlen = 1;
-+        m.msg_control = aux;
-+        m.msg_controllen = sizeof(aux);
-+
-+        p = pa_memblock_acquire(memchunk.memblock);
-+        iov.iov_base = p;
-+        iov.iov_len = pa_memblock_get_length(memchunk.memblock);
-+        l = recvmsg(u->stream_fd, &m, 0);
-+        pa_memblock_release(memchunk.memblock);
-+
-+        if (l <= 0) {
-+
-+            if (l < 0 && errno == EINTR)
-+                /* Retry right away if we got interrupted */
-+                continue;
-+
-+            else if (l < 0 && errno == EAGAIN)
-+                /* Hmm, apparently the socket was not readable, give up for now. */
-+                break;
-+
-+            pa_log_error("Failed to read data from SCO socket: %s", l < 0 ? pa_cstrerror(errno) : "EOF");
-+            ret = -1;
-+            break;
-+        }
-+
-+        pa_assert((size_t) l <= pa_memblock_get_length(memchunk.memblock));
-+
-+        /* In some rare occasions, we might receive packets of a very strange
-+         * size. This could potentially be possible if the SCO packet was
-+         * received partially over-the-air, or more probably due to hardware
-+         * issues in our Bluetooth adapter. In these cases, in order to avoid
-+         * an assertion failure due to unaligned data, just discard the whole
-+         * packet */
-+        if (!pa_frame_aligned(l, &u->sample_spec)) {
-+            pa_log_warn("SCO packet received of unaligned size: %zu", l);
-+            break;
-+        }
-+
-+        memchunk.length = (size_t) l;
-+        u->read_index += (uint64_t) l;
-+
-+        for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm))
-+            if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SO_TIMESTAMP) {
-+                struct timeval *tv = (struct timeval*) CMSG_DATA(cm);
-+                pa_rtclock_from_wallclock(tv);
-+                tstamp = pa_timeval_load(tv);
-+                found_tstamp = true;
-+                break;
-+            }
-+
-+        if (!found_tstamp) {
-+            pa_log_warn("Couldn't find SO_TIMESTAMP data in auxiliary recvmsg() data!");
-+            tstamp = pa_rtclock_now();
-+        }
-+
-+        pa_smoother_put(u->read_smoother, tstamp, pa_bytes_to_usec(u->read_index, &u->sample_spec));
-+        pa_smoother_resume(u->read_smoother, tstamp, true);
-+
-+        pa_source_post(u->source, &memchunk);
-+
-+        ret = l;
-+        break;
-+    }
-+
-+    pa_memblock_unref(memchunk.memblock);
-+
-+    return ret;
-+}
-+
-+/* Run from IO thread */
- static void a2dp_prepare_buffer(struct userdata *u) {
-     size_t min_buffer_size = PA_MAX(u->read_link_mtu, u->write_link_mtu);
-@@ -608,24 +772,31 @@ static void transport_release(struct userdata *u) {
- /* Run from I/O thread */
- static void transport_config_mtu(struct userdata *u) {
--    u->read_block_size =
--        (u->read_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
--        / u->sbc_info.frame_length * u->sbc_info.codesize;
-+    if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
-+        u->read_block_size = u->read_link_mtu;
-+        u->write_block_size = u->write_link_mtu;
-+    } else {
-+        u->read_block_size =
-+            (u->read_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
-+            / u->sbc_info.frame_length * u->sbc_info.codesize;
--    u->write_block_size =
--        (u->write_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
--        / u->sbc_info.frame_length * u->sbc_info.codesize;
-+        u->write_block_size =
-+            (u->write_link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
-+            / u->sbc_info.frame_length * u->sbc_info.codesize;
-+    }
-     if (u->sink) {
-         pa_sink_set_max_request_within_thread(u->sink, u->write_block_size);
-         pa_sink_set_fixed_latency_within_thread(u->sink,
--                                                FIXED_LATENCY_PLAYBACK_A2DP +
-+                                                (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK ?
-+                                                 FIXED_LATENCY_PLAYBACK_A2DP : FIXED_LATENCY_PLAYBACK_SCO) +
-                                                 pa_bytes_to_usec(u->write_block_size, &u->sample_spec));
-     }
-     if (u->source)
-         pa_source_set_fixed_latency_within_thread(u->source,
--                                                  FIXED_LATENCY_RECORD_A2DP +
-+                                                  (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE ?
-+                                                   FIXED_LATENCY_RECORD_A2DP : FIXED_LATENCY_RECORD_SCO) +
-                                                   pa_bytes_to_usec(u->read_block_size, &u->sample_spec));
- }
-@@ -752,15 +923,19 @@ static int add_source(struct userdata *u) {
-     data.namereg_fail = false;
-     pa_proplist_sets(data.proplist, "bluetooth.protocol", pa_bluetooth_profile_to_string(u->profile));
-     pa_source_new_data_set_sample_spec(&data, &u->sample_spec);
-+    if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT)
-+        pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
-     connect_ports(u, &data, PA_DIRECTION_INPUT);
-     if (!u->transport_acquired)
-         switch (u->profile) {
-             case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
-+            case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
-                 data.suspend_cause = PA_SUSPEND_USER;
-                 break;
-             case PA_BLUETOOTH_PROFILE_A2DP_SINK:
-+            case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
-             case PA_BLUETOOTH_PROFILE_OFF:
-                 pa_assert_not_reached();
-                 break;
-@@ -867,14 +1042,20 @@ static int add_sink(struct userdata *u) {
-     data.namereg_fail = false;
-     pa_proplist_sets(data.proplist, "bluetooth.protocol", pa_bluetooth_profile_to_string(u->profile));
-     pa_sink_new_data_set_sample_spec(&data, &u->sample_spec);
-+    if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT)
-+        pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
-     connect_ports(u, &data, PA_DIRECTION_OUTPUT);
-     if (!u->transport_acquired)
-         switch (u->profile) {
-+            case PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY:
-+                data.suspend_cause = PA_SUSPEND_USER;
-+                break;
-             case PA_BLUETOOTH_PROFILE_A2DP_SINK:
-                 /* Profile switch should have failed */
-             case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
-+            case PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT:
-             case PA_BLUETOOTH_PROFILE_OFF:
-                 pa_assert_not_reached();
-                 break;
-@@ -895,111 +1076,117 @@ static int add_sink(struct userdata *u) {
- /* Run from main thread */
- static void transport_config(struct userdata *u) {
--    sbc_info_t *sbc_info = &u->sbc_info;
--    a2dp_sbc_t *config;
-+    if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
-+        u->sample_spec.format = PA_SAMPLE_S16LE;
-+        u->sample_spec.channels = 1;
-+        u->sample_spec.rate = 8000;
-+    } else {
-+        sbc_info_t *sbc_info = &u->sbc_info;
-+        a2dp_sbc_t *config;
--    pa_assert(u->transport);
-+        pa_assert(u->transport);
--    u->sample_spec.format = PA_SAMPLE_S16LE;
--    config = (a2dp_sbc_t *) u->transport->config;
-+        u->sample_spec.format = PA_SAMPLE_S16LE;
-+        config = (a2dp_sbc_t *) u->transport->config;
--    if (sbc_info->sbc_initialized)
--        sbc_reinit(&sbc_info->sbc, 0);
--    else
--        sbc_init(&sbc_info->sbc, 0);
--    sbc_info->sbc_initialized = true;
-+        if (sbc_info->sbc_initialized)
-+            sbc_reinit(&sbc_info->sbc, 0);
-+        else
-+            sbc_init(&sbc_info->sbc, 0);
-+        sbc_info->sbc_initialized = true;
--    switch (config->frequency) {
--        case SBC_SAMPLING_FREQ_16000:
--            sbc_info->sbc.frequency = SBC_FREQ_16000;
--            u->sample_spec.rate = 16000U;
--            break;
--        case SBC_SAMPLING_FREQ_32000:
--            sbc_info->sbc.frequency = SBC_FREQ_32000;
--            u->sample_spec.rate = 32000U;
--            break;
--        case SBC_SAMPLING_FREQ_44100:
--            sbc_info->sbc.frequency = SBC_FREQ_44100;
--            u->sample_spec.rate = 44100U;
--            break;
--        case SBC_SAMPLING_FREQ_48000:
--            sbc_info->sbc.frequency = SBC_FREQ_48000;
--            u->sample_spec.rate = 48000U;
--            break;
--        default:
--            pa_assert_not_reached();
--    }
-+        switch (config->frequency) {
-+            case SBC_SAMPLING_FREQ_16000:
-+                sbc_info->sbc.frequency = SBC_FREQ_16000;
-+                u->sample_spec.rate = 16000U;
-+                break;
-+            case SBC_SAMPLING_FREQ_32000:
-+                sbc_info->sbc.frequency = SBC_FREQ_32000;
-+                u->sample_spec.rate = 32000U;
-+                break;
-+            case SBC_SAMPLING_FREQ_44100:
-+                sbc_info->sbc.frequency = SBC_FREQ_44100;
-+                u->sample_spec.rate = 44100U;
-+                break;
-+            case SBC_SAMPLING_FREQ_48000:
-+                sbc_info->sbc.frequency = SBC_FREQ_48000;
-+                u->sample_spec.rate = 48000U;
-+                break;
-+            default:
-+                pa_assert_not_reached();
-+        }
--    switch (config->channel_mode) {
--        case SBC_CHANNEL_MODE_MONO:
--            sbc_info->sbc.mode = SBC_MODE_MONO;
--            u->sample_spec.channels = 1;
--            break;
--        case SBC_CHANNEL_MODE_DUAL_CHANNEL:
--            sbc_info->sbc.mode = SBC_MODE_DUAL_CHANNEL;
--            u->sample_spec.channels = 2;
--            break;
--        case SBC_CHANNEL_MODE_STEREO:
--            sbc_info->sbc.mode = SBC_MODE_STEREO;
--            u->sample_spec.channels = 2;
--            break;
--        case SBC_CHANNEL_MODE_JOINT_STEREO:
--            sbc_info->sbc.mode = SBC_MODE_JOINT_STEREO;
--            u->sample_spec.channels = 2;
--            break;
--        default:
--            pa_assert_not_reached();
--    }
-+        switch (config->channel_mode) {
-+            case SBC_CHANNEL_MODE_MONO:
-+                sbc_info->sbc.mode = SBC_MODE_MONO;
-+                u->sample_spec.channels = 1;
-+                break;
-+            case SBC_CHANNEL_MODE_DUAL_CHANNEL:
-+                sbc_info->sbc.mode = SBC_MODE_DUAL_CHANNEL;
-+                u->sample_spec.channels = 2;
-+                break;
-+            case SBC_CHANNEL_MODE_STEREO:
-+                sbc_info->sbc.mode = SBC_MODE_STEREO;
-+                u->sample_spec.channels = 2;
-+                break;
-+            case SBC_CHANNEL_MODE_JOINT_STEREO:
-+                sbc_info->sbc.mode = SBC_MODE_JOINT_STEREO;
-+                u->sample_spec.channels = 2;
-+                break;
-+            default:
-+                pa_assert_not_reached();
-+        }
--    switch (config->allocation_method) {
--        case SBC_ALLOCATION_SNR:
--            sbc_info->sbc.allocation = SBC_AM_SNR;
--            break;
--        case SBC_ALLOCATION_LOUDNESS:
--            sbc_info->sbc.allocation = SBC_AM_LOUDNESS;
--            break;
--        default:
--            pa_assert_not_reached();
--    }
-+        switch (config->allocation_method) {
-+            case SBC_ALLOCATION_SNR:
-+                sbc_info->sbc.allocation = SBC_AM_SNR;
-+                break;
-+            case SBC_ALLOCATION_LOUDNESS:
-+                sbc_info->sbc.allocation = SBC_AM_LOUDNESS;
-+                break;
-+            default:
-+                pa_assert_not_reached();
-+        }
--    switch (config->subbands) {
--        case SBC_SUBBANDS_4:
--            sbc_info->sbc.subbands = SBC_SB_4;
--            break;
--        case SBC_SUBBANDS_8:
--            sbc_info->sbc.subbands = SBC_SB_8;
--            break;
--        default:
--            pa_assert_not_reached();
--    }
-+        switch (config->subbands) {
-+            case SBC_SUBBANDS_4:
-+                sbc_info->sbc.subbands = SBC_SB_4;
-+                break;
-+            case SBC_SUBBANDS_8:
-+                sbc_info->sbc.subbands = SBC_SB_8;
-+                break;
-+            default:
-+                pa_assert_not_reached();
-+        }
--    switch (config->block_length) {
--        case SBC_BLOCK_LENGTH_4:
--            sbc_info->sbc.blocks = SBC_BLK_4;
--            break;
--        case SBC_BLOCK_LENGTH_8:
--            sbc_info->sbc.blocks = SBC_BLK_8;
--            break;
--        case SBC_BLOCK_LENGTH_12:
--            sbc_info->sbc.blocks = SBC_BLK_12;
--            break;
--        case SBC_BLOCK_LENGTH_16:
--            sbc_info->sbc.blocks = SBC_BLK_16;
--            break;
--        default:
--            pa_assert_not_reached();
--    }
-+        switch (config->block_length) {
-+            case SBC_BLOCK_LENGTH_4:
-+                sbc_info->sbc.blocks = SBC_BLK_4;
-+                break;
-+            case SBC_BLOCK_LENGTH_8:
-+                sbc_info->sbc.blocks = SBC_BLK_8;
-+                break;
-+            case SBC_BLOCK_LENGTH_12:
-+                sbc_info->sbc.blocks = SBC_BLK_12;
-+                break;
-+            case SBC_BLOCK_LENGTH_16:
-+                sbc_info->sbc.blocks = SBC_BLK_16;
-+                break;
-+            default:
-+                pa_assert_not_reached();
-+        }
--    sbc_info->min_bitpool = config->min_bitpool;
--    sbc_info->max_bitpool = config->max_bitpool;
-+        sbc_info->min_bitpool = config->min_bitpool;
-+        sbc_info->max_bitpool = config->max_bitpool;
--    /* Set minimum bitpool for source to get the maximum possible block_size */
--    sbc_info->sbc.bitpool = u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK ? sbc_info->max_bitpool : sbc_info->min_bitpool;
--    sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc);
--    sbc_info->frame_length = sbc_get_frame_length(&sbc_info->sbc);
-+        /* Set minimum bitpool for source to get the maximum possible block_size */
-+        sbc_info->sbc.bitpool = u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK ? sbc_info->max_bitpool : sbc_info->min_bitpool;
-+        sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc);
-+        sbc_info->frame_length = sbc_get_frame_length(&sbc_info->sbc);
--    pa_log_info("SBC parameters: allocation=%u, subbands=%u, blocks=%u, bitpool=%u",
--                sbc_info->sbc.allocation, sbc_info->sbc.subbands, sbc_info->sbc.blocks, sbc_info->sbc.bitpool);
-+        pa_log_info("SBC parameters: allocation=%u, subbands=%u, blocks=%u, bitpool=%u",
-+                    sbc_info->sbc.allocation, sbc_info->sbc.subbands, sbc_info->sbc.blocks, sbc_info->sbc.bitpool);
-+    }
- }
- /* Run from main thread */
-@@ -1019,7 +1206,7 @@ static int setup_transport(struct userdata *u) {
-     u->transport = t;
--    if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE)
-+    if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
-         transport_acquire(u, true); /* In case of error, the sink/sources will be created suspended */
-     else if (transport_acquire(u, false) < 0)
-         return -1; /* We need to fail here until the interactions with module-suspend-on-idle and alike get improved */
-@@ -1040,11 +1227,13 @@ static int init_profile(struct userdata *u) {
-     pa_assert(u->transport);
--    if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK)
-+    if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
-+        u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
-         if (add_sink(u) < 0)
-             r = -1;
--    if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE)
-+    if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT ||
-+        u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
-         if (add_source(u) < 0)
-             r = -1;
-@@ -1090,7 +1279,10 @@ static void thread_func(void *userdata) {
-             if (pollfd && (pollfd->revents & POLLIN)) {
-                 int n_read;
--                n_read = a2dp_process_push(u);
-+                if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY)
-+                    n_read = sco_process_push(u);
-+                else
-+                    n_read = a2dp_process_push(u);
-                 if (n_read < 0)
-                     goto io_fail;
-@@ -1159,8 +1351,13 @@ static void thread_func(void *userdata) {
-                     if (u->write_index <= 0)
-                         u->started_at = pa_rtclock_now();
--                    if ((n_written = a2dp_process_render(u)) < 0)
--                        goto io_fail;
-+                    if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) {
-+                        if ((n_written = a2dp_process_render(u)) < 0)
-+                            goto io_fail;
-+                    } else {
-+                        if ((n_written = sco_process_render(u)) < 0)
-+                            goto io_fail;
-+                    }
-                     if (n_written == 0)
-                         pa_log("Broken kernel: we got EAGAIN on write() after POLLOUT!");
-@@ -1364,6 +1561,8 @@ static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) {
-     static const pa_direction_t profile_direction[] = {
-         [PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT,
-         [PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT,
-+        [PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
-+        [PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT,
-         [PA_BLUETOOTH_PROFILE_OFF] = 0
-     };
-@@ -1543,6 +1742,34 @@ static pa_card_profile *create_card_profile(struct userdata *u, const char *uuid
-         p = PA_CARD_PROFILE_DATA(cp);
-         *p = PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
-+    } else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF)) {
-+      /* TODO: Change this profile's name to headset_head_unit, to reflect the remote
-+         * device's role and be consistent with the other profiles */
-+        cp = pa_card_profile_new("hsp", _("Headset Head Unit (HSP/HFP)"), sizeof(enum profile));
-+        cp->priority = 20;
-+        cp->n_sinks = 1;
-+        cp->n_sources = 1;
-+        cp->max_sink_channels = 1;
-+        cp->max_source_channels = 1;
-+        pa_hashmap_put(input_port->profiles, cp->name, cp);
-+        pa_hashmap_put(output_port->profiles, cp->name, cp);
-+
-+        p = PA_CARD_PROFILE_DATA(cp);
-+        *p = PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT;
-+    } else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_AG) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_AG)) {
-+      /* TODO: Change this profile's name to headset_audio_gateway, to reflect the remote
-+         * device's role and be consistent with the other profiles */
-+        cp = pa_card_profile_new("hfgw", _("Headset Audio Gateway (HSP/HFP)"), sizeof(enum profile));
-+        cp->priority = 20;
-+        cp->n_sinks = 1;
-+        cp->n_sources = 1;
-+        cp->max_sink_channels = 1;
-+        cp->max_source_channels = 1;
-+        pa_hashmap_put(input_port->profiles, cp->name, cp);
-+        pa_hashmap_put(output_port->profiles, cp->name, cp);
-+
-+        p = PA_CARD_PROFILE_DATA(cp);
-+        *p = PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY;
-     }
-     if (cp && u->device->transports[*p])
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0011-bluetooth-Create-Handsfree-Audio-Agent-NULL-backend.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0011-bluetooth-Create-Handsfree-Audio-Agent-NULL-backend.patch
deleted file mode 100644 (file)
index 0ead373..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Tue, 9 Jul 2013 19:08:15 -0300
-Subject: bluetooth: Create Handsfree Audio Agent NULL backend
-
-Change-Id: I1f562a336f2cd2d0ab91c25fd5128da3cc7fe6df
----
- configure.ac                              | 10 +++++++++
- src/Makefile.am                           |  4 +++-
- src/modules/bluetooth/bluez5-util.c       |  6 +++++
- src/modules/bluetooth/hfaudioagent-null.c | 37 +++++++++++++++++++++++++++++++
- src/modules/bluetooth/hfaudioagent.h      | 31 ++++++++++++++++++++++++++
- 5 files changed, 87 insertions(+), 1 deletion(-)
- create mode 100644 src/modules/bluetooth/hfaudioagent-null.c
- create mode 100644 src/modules/bluetooth/hfaudioagent.h
-
-diff --git a/configure.ac b/configure.ac
-index 4e9f97e..a35918c 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1022,6 +1022,15 @@ AS_IF([test "x$HAVE_BLUEZ_4" = "x1" || test "x$HAVE_BLUEZ_5" = "x1"], HAVE_BLUEZ
- AC_SUBST(HAVE_BLUEZ)
- AM_CONDITIONAL([HAVE_BLUEZ], [test "x$HAVE_BLUEZ" = x1])
-+## Headset profiles backend ##
-+AC_ARG_WITH(bluetooth_headset_backend, AS_HELP_STRING([--with-bluetooth-headset-backend=<null|ofono>],[Backend for Bluetooth headset profiles (null)]))
-+if test -z "$with_bluetooth_headset_backend" ; then
-+    BLUETOOTH_HEADSET_BACKEND=null
-+else
-+    BLUETOOTH_HEADSET_BACKEND=$with_bluetooth_headset_backend
-+fi
-+AC_SUBST(BLUETOOTH_HEADSET_BACKEND)
-+
- #### UDEV support (optional) ####
- AC_ARG_ENABLE([udev],
-@@ -1486,6 +1495,7 @@ echo "
-     Enable D-Bus:                  ${ENABLE_DBUS}
-       Enable BlueZ 4:              ${ENABLE_BLUEZ_4}
-       Enable BlueZ 5:              ${ENABLE_BLUEZ_5}
-+        headset backed:            ${BLUETOOTH_HEADSET_BACKEND}
-     Enable udev:                   ${ENABLE_UDEV}
-       Enable HAL->udev compat:     ${ENABLE_HAL_COMPAT}
-     Enable systemd login:          ${ENABLE_SYSTEMD}
-diff --git a/src/Makefile.am b/src/Makefile.am
-index e1808e6..2edce5f 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -2074,7 +2074,9 @@ module_bluez4_device_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(SBC_CFLAGS)
- libbluez5_util_la_SOURCES = \
-               modules/bluetooth/bluez5-util.c \
-               modules/bluetooth/bluez5-util.h \
--              modules/bluetooth/a2dp-codecs.h
-+              modules/bluetooth/a2dp-codecs.h \
-+              modules/bluetooth/hfaudioagent.h \
-+              modules/bluetooth/hfaudioagent-@BLUETOOTH_HEADSET_BACKEND@.c
- libbluez5_util_la_LDFLAGS = -avoid-version
- libbluez5_util_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS)
- libbluez5_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
-diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c
-index ae219ea..35c8adf 100644
---- a/src/modules/bluetooth/bluez5-util.c
-+++ b/src/modules/bluetooth/bluez5-util.c
-@@ -34,6 +34,7 @@
- #include <pulsecore/shared.h>
- #include "a2dp-codecs.h"
-+#include "hfaudioagent.h"
- #include "bluez5-util.h"
-@@ -87,6 +88,7 @@ struct pa_bluetooth_discovery {
-     pa_hashmap *devices;
-     pa_hashmap *transports;
-+    hf_audio_agent_data *hf_audio_agent;
-     PA_LLIST_HEAD(pa_dbus_pending, pending);
- };
-@@ -1574,6 +1576,7 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
-     endpoint_init(y, PA_BLUETOOTH_PROFILE_A2DP_SINK);
-     endpoint_init(y, PA_BLUETOOTH_PROFILE_A2DP_SOURCE);
-+    y->hf_audio_agent = hf_audio_agent_init(c);
-     get_managed_objects(y);
-@@ -1615,6 +1618,9 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
-         pa_hashmap_free(y->transports);
-     }
-+    if (y->hf_audio_agent)
-+        hf_audio_agent_done(y->hf_audio_agent);
-+
-     if (y->connection) {
-         if (y->matches_added)
-diff --git a/src/modules/bluetooth/hfaudioagent-null.c b/src/modules/bluetooth/hfaudioagent-null.c
-new file mode 100644
-index 0000000..96fca06
---- /dev/null
-+++ b/src/modules/bluetooth/hfaudioagent-null.c
-@@ -0,0 +1,37 @@
-+/***
-+  This file is part of PulseAudio.
-+
-+  Copyright 2013 João Paulo Rechi Vita
-+
-+  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 <pulsecore/log.h>
-+
-+#include "hfaudioagent.h"
-+
-+hf_audio_agent_data *hf_audio_agent_init(pa_core *c) {
-+    pa_log_debug("HandsfreeAudioAgent API support disabled");
-+    return NULL;
-+}
-+
-+void hf_audio_agent_done(hf_audio_agent_data *data) {
-+    /* Nothing to do here */
-+}
-diff --git a/src/modules/bluetooth/hfaudioagent.h b/src/modules/bluetooth/hfaudioagent.h
-new file mode 100644
-index 0000000..2982034
---- /dev/null
-+++ b/src/modules/bluetooth/hfaudioagent.h
-@@ -0,0 +1,31 @@
-+#ifndef foohfagenthfoo
-+#define foohfagenthfoo
-+
-+/***
-+  This file is part of PulseAudio.
-+
-+  Copyright 2013 João Paulo Rechi Vita
-+
-+  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 hf_audio_agent_data hf_audio_agent_data;
-+
-+hf_audio_agent_data *hf_audio_agent_init(pa_core *c);
-+void hf_audio_agent_done(hf_audio_agent_data *data);
-+#endif
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0012-bluetooth-Create-Handsfree-Audio-Agent-oFono-backend.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0012-bluetooth-Create-Handsfree-Audio-Agent-oFono-backend.patch
deleted file mode 100644 (file)
index 39b938b..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Tue, 9 Jul 2013 20:22:17 -0300
-Subject: bluetooth: Create Handsfree Audio Agent oFono backend
-
-Change-Id: I2d5793e997205a04b37b9389ab75fc8643adcece
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 145 +++++++++++++++++++++++++++++
- 1 file changed, 145 insertions(+)
- create mode 100644 src/modules/bluetooth/hfaudioagent-ofono.c
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-new file mode 100644
-index 0000000..af78d4d
---- /dev/null
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -0,0 +1,145 @@
-+/***
-+  This file is part of PulseAudio.
-+
-+  Copyright 2013 João Paulo Rechi Vita
-+
-+  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 <pulsecore/core-util.h>
-+#include <pulsecore/dbus-shared.h>
-+
-+#include "hfaudioagent.h"
-+
-+#define OFONO_SERVICE "org.ofono"
-+#define HF_AUDIO_AGENT_INTERFACE OFONO_SERVICE ".HandsfreeAudioAgent"
-+
-+#define HF_AUDIO_AGENT_PATH "/HandsfreeAudioAgent"
-+
-+#define HF_AUDIO_AGENT_XML                                          \
-+    DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-+    "<node>"                                                        \
-+    "  <interface name=\"org.freedesktop.DBus.Introspectable\">"    \
-+    "    <method name=\"Introspect\">"                              \
-+    "      <arg direction=\"out\" type=\"s\" />"                    \
-+    "    </method>"                                                 \
-+    "  </interface>"                                                \
-+    "  <interface name=\"org.ofono.HandsfreeAudioAgent\">"          \
-+    "    <method name=\"Release\">"                                 \
-+    "    </method>"                                                 \
-+    "    <method name=\"NewConnection\">"                           \
-+    "      <arg direction=\"in\"  type=\"o\" name=\"card_path\" />" \
-+    "      <arg direction=\"in\"  type=\"h\" name=\"sco_fd\" />"    \
-+    "      <arg direction=\"in\"  type=\"y\" name=\"codec\" />"     \
-+    "    </method>"                                                 \
-+    "  </interface>"                                                \
-+    "</node>"
-+
-+struct hf_audio_agent_data {
-+    pa_core *core;
-+    pa_dbus_connection *connection;
-+};
-+
-+static DBusMessage *hf_audio_agent_release(DBusConnection *c, DBusMessage *m, void *data) {
-+    DBusMessage *r = dbus_message_new_error(m, "org.ofono.Error.NotImplemented", "Operation is not implemented");
-+    return r;
-+}
-+
-+static DBusMessage *hf_audio_agent_new_connection(DBusConnection *c, DBusMessage *m, void *data) {
-+    DBusMessage *r = dbus_message_new_error(m, "org.ofono.Error.NotImplemented", "Operation is not implemented");
-+    return r;
-+}
-+
-+static DBusHandlerResult hf_audio_agent_handler(DBusConnection *c, DBusMessage *m, void *data) {
-+    hf_audio_agent_data *hfdata = data;
-+    DBusMessage *r = NULL;
-+    const char *path, *interface, *member;
-+
-+    pa_assert(hfdata);
-+
-+    path = dbus_message_get_path(m);
-+    interface = dbus_message_get_interface(m);
-+    member = dbus_message_get_member(m);
-+
-+    if (!pa_streq(path, HF_AUDIO_AGENT_PATH))
-+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-+
-+    pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
-+
-+    if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
-+        const char *xml = HF_AUDIO_AGENT_XML;
-+
-+        pa_assert_se(r = dbus_message_new_method_return(m));
-+        pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
-+
-+    } else if (dbus_message_is_method_call(m, HF_AUDIO_AGENT_INTERFACE, "NewConnection"))
-+        r = hf_audio_agent_new_connection(c, m, data);
-+    else if (dbus_message_is_method_call(m, HF_AUDIO_AGENT_INTERFACE, "Release"))
-+        r = hf_audio_agent_release(c, m, data);
-+    else
-+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-+
-+    if (r) {
-+        pa_assert_se(dbus_connection_send(pa_dbus_connection_get(hfdata->connection), r, NULL));
-+        dbus_message_unref(r);
-+    }
-+
-+    return DBUS_HANDLER_RESULT_HANDLED;
-+}
-+
-+hf_audio_agent_data *hf_audio_agent_init(pa_core *c) {
-+    hf_audio_agent_data *hfdata;
-+    DBusError err;
-+    static const DBusObjectPathVTable vtable_hf_audio_agent = {
-+        .message_function = hf_audio_agent_handler,
-+    };
-+
-+    pa_assert(c);
-+
-+    hfdata = pa_xnew0(hf_audio_agent_data, 1);
-+    hfdata->core = c;
-+
-+    dbus_error_init(&err);
-+
-+    if (!(hfdata->connection = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &err))) {
-+        pa_log("Failed to get D-Bus connection: %s", err.message);
-+        dbus_error_free(&err);
-+        return NULL;
-+    }
-+
-+    pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(hfdata->connection), HF_AUDIO_AGENT_PATH,
-+                                                      &vtable_hf_audio_agent, hfdata));
-+
-+    return hfdata;
-+}
-+
-+void hf_audio_agent_done(hf_audio_agent_data *data) {
-+    hf_audio_agent_data *hfdata = data;
-+
-+    pa_assert(hfdata);
-+
-+    if (hfdata->connection) {
-+        dbus_connection_unregister_object_path(pa_dbus_connection_get(hfdata->connection), HF_AUDIO_AGENT_PATH);
-+
-+        pa_dbus_connection_unref(hfdata->connection);
-+    }
-+
-+    pa_xfree(hfdata);
-+}
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0013-bluetooth-Monitor-D-Bus-signals.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0013-bluetooth-Monitor-D-Bus-signals.patch
deleted file mode 100644 (file)
index 0a93d5c..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Wed, 10 Jul 2013 12:18:07 -0300
-Subject: bluetooth: Monitor D-Bus signals
-
-Change-Id: Ibfd4ab9acaf49df0fdfaff55609c560ab31f4df4
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 48 ++++++++++++++++++++++++++++++
- 1 file changed, 48 insertions(+)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index af78d4d..0e3ffc4 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -30,6 +30,7 @@
- #define OFONO_SERVICE "org.ofono"
- #define HF_AUDIO_AGENT_INTERFACE OFONO_SERVICE ".HandsfreeAudioAgent"
-+#define HF_AUDIO_MANAGER_INTERFACE OFONO_SERVICE ".HandsfreeAudioManager"
- #define HF_AUDIO_AGENT_PATH "/HandsfreeAudioAgent"
-@@ -55,8 +56,18 @@
- struct hf_audio_agent_data {
-     pa_core *core;
-     pa_dbus_connection *connection;
-+
-+    bool filter_added;
-+    pa_hashmap *hf_audio_cards;
- };
-+static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *data) {
-+    pa_assert(bus);
-+    pa_assert(m);
-+
-+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-+}
-+
- static DBusMessage *hf_audio_agent_release(DBusConnection *c, DBusMessage *m, void *data) {
-     DBusMessage *r = dbus_message_new_error(m, "org.ofono.Error.NotImplemented", "Operation is not implemented");
-     return r;
-@@ -115,6 +126,7 @@ hf_audio_agent_data *hf_audio_agent_init(pa_core *c) {
-     hfdata = pa_xnew0(hf_audio_agent_data, 1);
-     hfdata->core = c;
-+    hfdata->hf_audio_cards = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-     dbus_error_init(&err);
-@@ -124,6 +136,25 @@ hf_audio_agent_data *hf_audio_agent_init(pa_core *c) {
-         return NULL;
-     }
-+    /* dynamic detection of handsfree audio cards */
-+    if (!dbus_connection_add_filter(pa_dbus_connection_get(hfdata->connection), filter_cb, hfdata, NULL)) {
-+        pa_log_error("Failed to add filter function");
-+        hf_audio_agent_done(hfdata);
-+        return NULL;
-+    }
-+    hfdata->filter_added = true;
-+
-+    if (pa_dbus_add_matches(pa_dbus_connection_get(hfdata->connection), &err,
-+            "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',"
-+            "arg0='" OFONO_SERVICE "'",
-+            "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardAdded'",
-+            "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardRemoved'",
-+            NULL) < 0) {
-+        pa_log("Failed to add oFono D-Bus matches: %s", err.message);
-+        hf_audio_agent_done(hfdata);
-+        return NULL;
-+    }
-+
-     pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(hfdata->connection), HF_AUDIO_AGENT_PATH,
-                                                       &vtable_hf_audio_agent, hfdata));
-@@ -135,7 +166,24 @@ void hf_audio_agent_done(hf_audio_agent_data *data) {
-     pa_assert(hfdata);
-+    if (hfdata->hf_audio_cards) {
-+        pa_hashmap_free(hfdata->hf_audio_cards, NULL);
-+        hfdata->hf_audio_cards = NULL;
-+    }
-+
-     if (hfdata->connection) {
-+
-+        pa_dbus_remove_matches(
-+            pa_dbus_connection_get(hfdata->connection),
-+            "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',"
-+            "arg0='" OFONO_SERVICE "'",
-+            "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardAdded'",
-+            "type='signal',sender='" OFONO_SERVICE "',interface='" HF_AUDIO_MANAGER_INTERFACE "',member='CardRemoved'",
-+            NULL);
-+
-+        if (hfdata->filter_added)
-+            dbus_connection_remove_filter(pa_dbus_connection_get(hfdata->connection), filter_cb, hfdata);
-+
-         dbus_connection_unregister_object_path(pa_dbus_connection_get(hfdata->connection), HF_AUDIO_AGENT_PATH);
-         pa_dbus_connection_unref(hfdata->connection);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0014-bluetooth-Create-pa_bluetooth_dbus_send_and_add_to_p.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0014-bluetooth-Create-pa_bluetooth_dbus_send_and_add_to_p.patch
deleted file mode 100644 (file)
index c9d893c..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Wed, 10 Jul 2013 13:00:16 -0300
-Subject: bluetooth: Create pa_bluetooth_dbus_send_and_add_to_pending() for
- oFono backend
-
-Change-Id: I9b6ea22d6bd1059e5d7b3a12ec13b2768cacce0d
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 21 +++++++++++++++++++++
- 1 file changed, 21 insertions(+)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index 0e3ffc4..38975b2 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -59,8 +59,27 @@ struct hf_audio_agent_data {
-     bool filter_added;
-     pa_hashmap *hf_audio_cards;
-+
-+    PA_LLIST_HEAD(pa_dbus_pending, pending);
- };
-+static pa_dbus_pending* pa_bluetooth_dbus_send_and_add_to_pending(hf_audio_agent_data *hfdata, DBusMessage *m,
-+                                                                  DBusPendingCallNotifyFunction func, void *call_data) {
-+    pa_dbus_pending *p;
-+    DBusPendingCall *call;
-+
-+    pa_assert(hfdata);
-+    pa_assert(m);
-+
-+    pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(hfdata->connection), m, &call, -1));
-+
-+    p = pa_dbus_pending_new(pa_dbus_connection_get(hfdata->connection), m, call, hfdata, call_data);
-+    PA_LLIST_PREPEND(pa_dbus_pending, hfdata->pending, p);
-+    dbus_pending_call_set_notify(call, func, p, NULL);
-+
-+    return p;
-+}
-+
- static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *data) {
-     pa_assert(bus);
-     pa_assert(m);
-@@ -166,6 +185,8 @@ void hf_audio_agent_done(hf_audio_agent_data *data) {
-     pa_assert(hfdata);
-+    pa_dbus_free_pending_list(&hfdata->pending);
-+
-     if (hfdata->hf_audio_cards) {
-         pa_hashmap_free(hfdata->hf_audio_cards, NULL);
-         hfdata->hf_audio_cards = NULL;
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0015-bluetooth-Register-Unregister-Handsfree-Audio-Agent-.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0015-bluetooth-Register-Unregister-Handsfree-Audio-Agent-.patch
deleted file mode 100644 (file)
index 931069c..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Tue, 9 Jul 2013 20:59:12 -0300
-Subject: bluetooth: Register/Unregister Handsfree Audio Agent with oFono
-
-Register as a HandsfreeAudioAgent with oFono during backend
-initialization and unregiter during backend finalization. This commit
-also adds a check when receiving method calls or signals to make sure
-the sender matches with the D-Bus service we're registered with.
-
-Change-Id: I0a49935702ffb52d6d2ba1baded8eb568262c5b1
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 107 ++++++++++++++++++++++++++++-
- 1 file changed, 105 insertions(+), 2 deletions(-)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index 38975b2..de58e7d 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -28,6 +28,9 @@
- #include "hfaudioagent.h"
-+#define HFP_AUDIO_CODEC_CVSD    0x01
-+#define HFP_AUDIO_CODEC_MSBC    0x02
-+
- #define OFONO_SERVICE "org.ofono"
- #define HF_AUDIO_AGENT_INTERFACE OFONO_SERVICE ".HandsfreeAudioAgent"
- #define HF_AUDIO_MANAGER_INTERFACE OFONO_SERVICE ".HandsfreeAudioManager"
-@@ -58,6 +61,7 @@ struct hf_audio_agent_data {
-     pa_dbus_connection *connection;
-     bool filter_added;
-+    char *ofono_bus_id;
-     pa_hashmap *hf_audio_cards;
-     PA_LLIST_HEAD(pa_dbus_pending, pending);
-@@ -80,20 +84,115 @@ static pa_dbus_pending* pa_bluetooth_dbus_send_and_add_to_pending(hf_audio_agent
-     return p;
- }
-+static void hf_audio_agent_register_reply(DBusPendingCall *pending, void *userdata) {
-+    DBusMessage *r;
-+    pa_dbus_pending *p;
-+    hf_audio_agent_data *hfdata;
-+
-+    pa_assert_se(p = userdata);
-+    pa_assert_se(hfdata = p->context_data);
-+    pa_assert_se(r = dbus_pending_call_steal_reply(pending));
-+
-+    if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
-+        pa_log_error("Failed to register as a handsfree audio agent with ofono: %s: %s",
-+                     dbus_message_get_error_name(r), pa_dbus_get_error_message(r));
-+        goto finish;
-+    }
-+
-+    hfdata->ofono_bus_id = pa_xstrdup(dbus_message_get_sender(r));
-+
-+    /* TODO: List all HandsfreeAudioCard objects */
-+
-+finish:
-+    dbus_message_unref(r);
-+
-+    PA_LLIST_REMOVE(pa_dbus_pending, hfdata->pending, p);
-+    pa_dbus_pending_free(p);
-+}
-+
-+static void hf_audio_agent_register(hf_audio_agent_data *hfdata) {
-+    DBusMessage *m;
-+    unsigned char codecs[2];
-+    const unsigned char *pcodecs = codecs;
-+    int ncodecs = 0;
-+    const char *path = HF_AUDIO_AGENT_PATH;
-+
-+    pa_assert(hfdata);
-+
-+    pa_assert_se(m = dbus_message_new_method_call(OFONO_SERVICE, "/", HF_AUDIO_MANAGER_INTERFACE, "Register"));
-+
-+    codecs[ncodecs++] = HFP_AUDIO_CODEC_CVSD;
-+    codecs[ncodecs++] = HFP_AUDIO_CODEC_MSBC;
-+
-+    pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pcodecs, ncodecs,
-+                                          DBUS_TYPE_INVALID));
-+
-+    pa_bluetooth_dbus_send_and_add_to_pending(hfdata, m, hf_audio_agent_register_reply, NULL);
-+}
-+
-+static void hf_audio_agent_unregister(hf_audio_agent_data *hfdata) {
-+    DBusMessage *m;
-+    const char *path = HF_AUDIO_AGENT_PATH;
-+
-+    pa_assert(hfdata);
-+    pa_assert(hfdata->connection);
-+
-+    if (hfdata->ofono_bus_id) {
-+        pa_assert_se(m = dbus_message_new_method_call(hfdata->ofono_bus_id, "/", HF_AUDIO_MANAGER_INTERFACE, "Unregister"));
-+        pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID));
-+        pa_assert_se(dbus_connection_send(pa_dbus_connection_get(hfdata->connection), m, NULL));
-+
-+        pa_xfree(hfdata->ofono_bus_id);
-+        hfdata->ofono_bus_id = NULL;
-+    }
-+}
-+
- static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *data) {
-+    const char *sender;
-+    hf_audio_agent_data *hfdata = data;
-+
-     pa_assert(bus);
-     pa_assert(m);
-+    pa_assert(hfdata);
-+
-+    sender = dbus_message_get_sender(m);
-+    if (!pa_safe_streq(hfdata->ofono_bus_id, sender) && !pa_streq("org.freedesktop.DBus", sender))
-+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
- static DBusMessage *hf_audio_agent_release(DBusConnection *c, DBusMessage *m, void *data) {
--    DBusMessage *r = dbus_message_new_error(m, "org.ofono.Error.NotImplemented", "Operation is not implemented");
-+    DBusMessage *r;
-+    const char *sender;
-+    hf_audio_agent_data *hfdata = data;
-+
-+    pa_assert(hfdata);
-+
-+    sender = dbus_message_get_sender(m);
-+    if (!pa_streq(hfdata->ofono_bus_id, sender)) {
-+        pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.NotAllowed", "Operation is not allowed by this sender"));
-+        return r;
-+    }
-+
-+    r = dbus_message_new_error(m, "org.ofono.Error.NotImplemented", "Operation is not implemented");
-     return r;
- }
- static DBusMessage *hf_audio_agent_new_connection(DBusConnection *c, DBusMessage *m, void *data) {
--    DBusMessage *r = dbus_message_new_error(m, "org.ofono.Error.NotImplemented", "Operation is not implemented");
-+    DBusMessage *r;
-+    const char *sender;
-+    hf_audio_agent_data *hfdata = data;
-+
-+    pa_assert(hfdata);
-+
-+    sender = dbus_message_get_sender(m);
-+    if (!pa_streq(hfdata->ofono_bus_id, sender)) {
-+        pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.NotAllowed", "Operation is not allowed by this sender"));
-+        return r;
-+    }
-+
-+    r = dbus_message_new_error(m, "org.ofono.Error.NotImplemented", "Operation is not implemented");
-     return r;
- }
-@@ -177,6 +276,8 @@ hf_audio_agent_data *hf_audio_agent_init(pa_core *c) {
-     pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(hfdata->connection), HF_AUDIO_AGENT_PATH,
-                                                       &vtable_hf_audio_agent, hfdata));
-+    hf_audio_agent_register(hfdata);
-+
-     return hfdata;
- }
-@@ -205,6 +306,8 @@ void hf_audio_agent_done(hf_audio_agent_data *data) {
-         if (hfdata->filter_added)
-             dbus_connection_remove_filter(pa_dbus_connection_get(hfdata->connection), filter_cb, hfdata);
-+        hf_audio_agent_unregister(hfdata);
-+
-         dbus_connection_unregister_object_path(pa_dbus_connection_get(hfdata->connection), HF_AUDIO_AGENT_PATH);
-         pa_dbus_connection_unref(hfdata->connection);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0016-bluetooth-List-HandsfreeAudioCard-objects-from-oFono.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0016-bluetooth-List-HandsfreeAudioCard-objects-from-oFono.patch
deleted file mode 100644 (file)
index d943ce4..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Tue, 9 Jul 2013 21:03:28 -0300
-Subject: bluetooth: List HandsfreeAudioCard objects from oFono
-
-Change-Id: Idb2423d8b5640486976df5347e2f7d05a9e6dd71
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 71 +++++++++++++++++++++++++++++-
- 1 file changed, 70 insertions(+), 1 deletion(-)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index de58e7d..6b27f80 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -84,6 +84,75 @@ static pa_dbus_pending* pa_bluetooth_dbus_send_and_add_to_pending(hf_audio_agent
-     return p;
- }
-+static void hf_audio_agent_get_cards_reply(DBusPendingCall *pending, void *userdata) {
-+    DBusMessage *r;
-+    pa_dbus_pending *p;
-+    hf_audio_agent_data *hfdata;
-+    DBusMessageIter i, array_i, struct_i, props_i;
-+    char c;
-+
-+    pa_assert_se(p = userdata);
-+    pa_assert_se(hfdata = p->context_data);
-+    pa_assert_se(r = dbus_pending_call_steal_reply(pending));
-+
-+    if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
-+        pa_log_error("Failed to get a list of handsfree audio cards from ofono: %s: %s",
-+                     dbus_message_get_error_name(r), pa_dbus_get_error_message(r));
-+        goto finish;
-+    }
-+
-+    dbus_message_iter_init(r, &i);
-+    if ((c = dbus_message_iter_get_arg_type(&i)) != DBUS_TYPE_ARRAY) {
-+        pa_log_error("Invalid arguments in GetCards() reply: expected \'a\', received \'%c\'", c);
-+        goto finish;
-+    }
-+
-+    dbus_message_iter_recurse(&i, &array_i);
-+    while (dbus_message_iter_get_arg_type(&array_i) != DBUS_TYPE_INVALID) {
-+        const char *path;
-+
-+        if ((c = dbus_message_iter_get_arg_type(&array_i)) != DBUS_TYPE_STRUCT) {
-+            pa_log_error("Invalid arguments in GetCards() reply: expected \'r\', received \'%c\'", c);
-+            goto finish;
-+        }
-+
-+        dbus_message_iter_recurse(&array_i, &struct_i);
-+        if ((c = dbus_message_iter_get_arg_type(&struct_i)) != DBUS_TYPE_OBJECT_PATH) {
-+            pa_log_error("Invalid arguments in GetCards() reply: expected \'o\', received \'%c\'", c);
-+            goto finish;
-+        }
-+
-+        dbus_message_iter_get_basic(&struct_i, &path);
-+
-+        dbus_message_iter_next(&struct_i);
-+        if ((c = dbus_message_iter_get_arg_type(&struct_i)) != DBUS_TYPE_ARRAY) {
-+            pa_log_error("Invalid arguments in GetCards() reply: expected \'a\', received \'%c\'", c);
-+            goto finish;
-+        }
-+
-+        dbus_message_iter_recurse(&struct_i, &props_i);
-+
-+        /* TODO: Parse HandsfreeAudioCard properties */
-+
-+        dbus_message_iter_next(&array_i);
-+    }
-+
-+finish:
-+    dbus_message_unref(r);
-+
-+    PA_LLIST_REMOVE(pa_dbus_pending, hfdata->pending, p);
-+    pa_dbus_pending_free(p);
-+}
-+
-+static void hf_audio_agent_get_cards(hf_audio_agent_data *hfdata) {
-+    DBusMessage *m;
-+
-+    pa_assert(hfdata);
-+
-+    pa_assert_se(m = dbus_message_new_method_call(OFONO_SERVICE, "/", HF_AUDIO_MANAGER_INTERFACE, "GetCards"));
-+    pa_bluetooth_dbus_send_and_add_to_pending(hfdata, m, hf_audio_agent_get_cards_reply, NULL);
-+}
-+
- static void hf_audio_agent_register_reply(DBusPendingCall *pending, void *userdata) {
-     DBusMessage *r;
-     pa_dbus_pending *p;
-@@ -101,7 +170,7 @@ static void hf_audio_agent_register_reply(DBusPendingCall *pending, void *userda
-     hfdata->ofono_bus_id = pa_xstrdup(dbus_message_get_sender(r));
--    /* TODO: List all HandsfreeAudioCard objects */
-+    hf_audio_agent_get_cards(hfdata);
- finish:
-     dbus_message_unref(r);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0017-bluetooth-Parse-HandsfreeAudioCard-properties.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0017-bluetooth-Parse-HandsfreeAudioCard-properties.patch
deleted file mode 100644 (file)
index f7a2174..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Tue, 9 Jul 2013 21:37:26 -0300
-Subject: bluetooth: Parse HandsfreeAudioCard properties
-
-Change-Id: I37600ca3ab60d1b82608f4e395fa427fdaf62164
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 128 ++++++++++++++++++++++++++++-
- 1 file changed, 126 insertions(+), 2 deletions(-)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index 6b27f80..2e16a48 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -25,6 +25,9 @@
- #include <pulsecore/core-util.h>
- #include <pulsecore/dbus-shared.h>
-+#include <pulsecore/shared.h>
-+
-+#include "bluez5-util.h"
- #include "hfaudioagent.h"
-@@ -56,9 +59,21 @@
-     "  </interface>"                                                \
-     "</node>"
-+typedef struct hf_audio_card {
-+    char *path;
-+    char *remote;
-+    char *local;
-+
-+    int fd;
-+    uint8_t codec;
-+
-+    pa_bluetooth_transport *transport;
-+} hf_audio_card;
-+
- struct hf_audio_agent_data {
-     pa_core *core;
-     pa_dbus_connection *connection;
-+    pa_bluetooth_discovery *discovery;
-     bool filter_added;
-     char *ofono_bus_id;
-@@ -84,6 +99,111 @@ static pa_dbus_pending* pa_bluetooth_dbus_send_and_add_to_pending(hf_audio_agent
-     return p;
- }
-+static hf_audio_card *hf_audio_card_new(hf_audio_agent_data *hfdata, const char *path) {
-+    hf_audio_card *hfac = pa_xnew0(hf_audio_card, 1);
-+
-+    hfac->path = pa_xstrdup(path);
-+    hfac->fd = -1;
-+
-+    return hfac;
-+}
-+
-+static void hf_audio_card_free(void *data) {
-+    hf_audio_card *hfac = data;
-+
-+    pa_assert(hfac);
-+
-+    pa_bluetooth_transport_free(hfac->transport);
-+    pa_xfree(hfac->path);
-+    pa_xfree(hfac->remote);
-+    pa_xfree(hfac->local);
-+    pa_xfree(hfac);
-+}
-+
-+static int hf_audio_agent_transport_acquire(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) {
-+    return -1;
-+}
-+
-+static void hf_audio_agent_transport_release(pa_bluetooth_transport *t) {
-+}
-+
-+static void hf_audio_agent_card_found(hf_audio_agent_data *hfdata, const char *path, DBusMessageIter *props_i) {
-+    DBusMessageIter i, value_i;
-+    const char *key, *value;
-+    hf_audio_card *hfac;
-+    pa_bluetooth_device *d;
-+
-+    pa_assert(hfdata);
-+    pa_assert(path);
-+    pa_assert(props_i);
-+
-+    pa_log_debug("New HF card found: %s", path);
-+
-+    hfac = hf_audio_card_new(hfdata, path);
-+
-+    while (dbus_message_iter_get_arg_type(props_i) != DBUS_TYPE_INVALID) {
-+        char c;
-+
-+        if ((c = dbus_message_iter_get_arg_type(props_i)) != DBUS_TYPE_DICT_ENTRY) {
-+            pa_log_error("Invalid properties for %s: expected \'e\', received \'%c\'", path, c);
-+            goto fail;
-+        }
-+
-+        dbus_message_iter_recurse(props_i, &i);
-+
-+        if ((c = dbus_message_iter_get_arg_type(&i)) != DBUS_TYPE_STRING) {
-+            pa_log_error("Invalid properties for %s: expected \'s\', received \'%c\'", path, c);
-+            goto fail;
-+        }
-+
-+        dbus_message_iter_get_basic(&i, &key);
-+        dbus_message_iter_next(&i);
-+
-+        if ((c = dbus_message_iter_get_arg_type(&i)) != DBUS_TYPE_VARIANT) {
-+            pa_log_error("Invalid properties for %s: expected \'v\', received \'%c\'", path, c);
-+            goto fail;
-+        }
-+
-+        dbus_message_iter_recurse(&i, &value_i);
-+
-+        if ((c = dbus_message_iter_get_arg_type(&value_i)) != DBUS_TYPE_STRING) {
-+            pa_log_error("Invalid properties for %s: expected \'s\', received \'%c\'", path, c);
-+            goto fail;
-+        }
-+
-+        dbus_message_iter_get_basic(&value_i, &value);
-+
-+        if (pa_streq(key, "RemoteAddress"))
-+            hfac->remote = pa_xstrdup(value);
-+        else if (pa_streq(key, "LocalAddress"))
-+            hfac->local = pa_xstrdup(value);
-+
-+        pa_log_debug("%s: %s", key, value);
-+
-+        dbus_message_iter_next(props_i);
-+    }
-+
-+    pa_hashmap_put(hfdata->hf_audio_cards, hfac->path, hfac);
-+
-+    d = pa_bluetooth_discovery_get_device_by_address(hfdata->discovery, hfac->remote, hfac->local);
-+    if (d) {
-+        hfac->transport = pa_bluetooth_transport_new(d, hfdata->ofono_bus_id, path, PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY, NULL, 0);
-+        hfac->transport->acquire = hf_audio_agent_transport_acquire;
-+        hfac->transport->release = hf_audio_agent_transport_release;
-+        hfac->transport->userdata = hfdata;
-+
-+        d->transports[PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = hfac->transport;
-+
-+        pa_bluetooth_transport_put(hfac->transport);
-+    } else
-+        pa_log_error("Device doesnt exist for %s", path);
-+
-+    return;
-+
-+fail:
-+    pa_xfree(hfac);
-+}
-+
- static void hf_audio_agent_get_cards_reply(DBusPendingCall *pending, void *userdata) {
-     DBusMessage *r;
-     pa_dbus_pending *p;
-@@ -132,7 +252,7 @@ static void hf_audio_agent_get_cards_reply(DBusPendingCall *pending, void *userd
-         dbus_message_iter_recurse(&struct_i, &props_i);
--        /* TODO: Parse HandsfreeAudioCard properties */
-+        hf_audio_agent_card_found(hfdata, path, &props_i);
-         dbus_message_iter_next(&array_i);
-     }
-@@ -314,6 +434,7 @@ hf_audio_agent_data *hf_audio_agent_init(pa_core *c) {
-     hfdata = pa_xnew0(hf_audio_agent_data, 1);
-     hfdata->core = c;
-     hfdata->hf_audio_cards = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-+    hfdata->discovery = pa_shared_get(c, "bluetooth-discovery");
-     dbus_error_init(&err);
-@@ -358,7 +479,7 @@ void hf_audio_agent_done(hf_audio_agent_data *data) {
-     pa_dbus_free_pending_list(&hfdata->pending);
-     if (hfdata->hf_audio_cards) {
--        pa_hashmap_free(hfdata->hf_audio_cards, NULL);
-+        pa_hashmap_free(hfdata->hf_audio_cards, hf_audio_card_free);
-         hfdata->hf_audio_cards = NULL;
-     }
-@@ -382,5 +503,8 @@ void hf_audio_agent_done(hf_audio_agent_data *data) {
-         pa_dbus_connection_unref(hfdata->connection);
-     }
-+    if (hfdata->discovery)
-+        hfdata->discovery = NULL;
-+
-     pa_xfree(hfdata);
- }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0018-bluetooth-Implement-transport-acquire-for-hf_audio_a.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0018-bluetooth-Implement-transport-acquire-for-hf_audio_a.patch
deleted file mode 100644 (file)
index c3815cc..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Tue, 9 Jul 2013 22:22:28 -0300
-Subject: bluetooth: Implement transport acquire for hf_audio_agent transports
-
-Change-Id: Ia092e75c51f79d1a594ba6dacda55ec03a5dae93
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 28 +++++++++++++++++++++++++++-
- 1 file changed, 27 insertions(+), 1 deletion(-)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index 2e16a48..3684bed 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -121,7 +121,33 @@ static void hf_audio_card_free(void *data) {
- }
- static int hf_audio_agent_transport_acquire(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) {
--    return -1;
-+    hf_audio_agent_data *hfdata = t->userdata;
-+    hf_audio_card *hfac = pa_hashmap_get(hfdata->hf_audio_cards, t->path);
-+
-+    if (!optional) {
-+        DBusMessage *m;
-+
-+        pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.ofono.HandsfreeAudioCard", "Connect"));
-+        pa_assert_se(dbus_connection_send(pa_dbus_connection_get(hfdata->connection), m, NULL));
-+
-+        return -1;
-+    }
-+
-+    /* The correct block size should take into account the SCO MTU from
-+     * the Bluetooth adapter and (for adapters in the USB bus) the MxPS
-+     * value from the Isoc USB endpoint in use by btusb and should be
-+     * made available to userspace by the Bluetooth kernel subsystem.
-+     * Meanwhile the empiric value 48 will be used. */
-+    if (imtu)
-+        *imtu = 48;
-+    if (omtu)
-+        *omtu = 48;
-+
-+    if (hfac) {
-+        t->codec = hfac->codec;
-+        return hfac->fd;
-+    } else
-+        return -1;
- }
- static void hf_audio_agent_transport_release(pa_bluetooth_transport *t) {
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0019-bluetooth-Track-oFono-service.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0019-bluetooth-Track-oFono-service.patch
deleted file mode 100644 (file)
index 5f8fa21..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Thu, 11 Jul 2013 11:43:48 -0300
-Subject: bluetooth: Track oFono service
-
-Change-Id: I6752f21b848757dbea20c92c68b581141cefbc67
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 61 ++++++++++++++++++++++++++++--
- 1 file changed, 58 insertions(+), 3 deletions(-)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index 3684bed..97e0fa8 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -364,6 +364,7 @@ static void hf_audio_agent_unregister(hf_audio_agent_data *hfdata) {
- static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *data) {
-     const char *sender;
-+    DBusError err;
-     hf_audio_agent_data *hfdata = data;
-     pa_assert(bus);
-@@ -374,6 +375,46 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *da
-     if (!pa_safe_streq(hfdata->ofono_bus_id, sender) && !pa_streq("org.freedesktop.DBus", sender))
-         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-+    dbus_error_init(&err);
-+
-+    if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) {
-+        const char *name, *old_owner, *new_owner;
-+
-+        if (!dbus_message_get_args(m, &err,
-+                                   DBUS_TYPE_STRING, &name,
-+                                   DBUS_TYPE_STRING, &old_owner,
-+                                   DBUS_TYPE_STRING, &new_owner,
-+                                   DBUS_TYPE_INVALID)) {
-+            pa_log_error("Failed to parse org.freedesktop.DBus.NameOwnerChanged: %s", err.message);
-+            goto fail;
-+        }
-+
-+        if (pa_streq(name, OFONO_SERVICE)) {
-+
-+            if (old_owner && *old_owner) {
-+                pa_log_debug("oFono disappeared");
-+
-+                if (hfdata->hf_audio_cards) {
-+                    pa_hashmap_free(hfdata->hf_audio_cards);
-+                    hfdata->hf_audio_cards = NULL;
-+                }
-+
-+                if(hfdata->ofono_bus_id) {
-+                    pa_xfree(hfdata->ofono_bus_id);
-+                    hfdata->ofono_bus_id = NULL;
-+                }
-+            }
-+
-+            if (new_owner && *new_owner) {
-+                pa_log_debug("oFono appeared");
-+                hf_audio_agent_register(hfdata);
-+            }
-+        }
-+
-+    }
-+
-+fail:
-+    dbus_error_free(&err);
-     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-@@ -390,7 +431,20 @@ static DBusMessage *hf_audio_agent_release(DBusConnection *c, DBusMessage *m, vo
-         return r;
-     }
--    r = dbus_message_new_error(m, "org.ofono.Error.NotImplemented", "Operation is not implemented");
-+    pa_log_debug("HF audio agent has been unregistered by oFono (%s)", hfdata->ofono_bus_id);
-+
-+    if (hfdata->hf_audio_cards) {
-+        pa_hashmap_free(hfdata->hf_audio_cards);
-+        hfdata->hf_audio_cards = NULL;
-+    }
-+
-+    if(hfdata->ofono_bus_id) {
-+        pa_xfree(hfdata->ofono_bus_id);
-+        hfdata->ofono_bus_id = NULL;
-+    }
-+
-+    pa_assert_se(r = dbus_message_new_method_return(m));
-+
-     return r;
- }
-@@ -459,7 +513,8 @@ hf_audio_agent_data *hf_audio_agent_init(pa_core *c) {
-     hfdata = pa_xnew0(hf_audio_agent_data, 1);
-     hfdata->core = c;
--    hfdata->hf_audio_cards = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-+    hfdata->hf_audio_cards = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func,
-+                                                 NULL, hf_audio_card_free);
-     hfdata->discovery = pa_shared_get(c, "bluetooth-discovery");
-     dbus_error_init(&err);
-@@ -505,7 +560,7 @@ void hf_audio_agent_done(hf_audio_agent_data *data) {
-     pa_dbus_free_pending_list(&hfdata->pending);
-     if (hfdata->hf_audio_cards) {
--        pa_hashmap_free(hfdata->hf_audio_cards, hf_audio_card_free);
-+        pa_hashmap_free(hfdata->hf_audio_cards);
-         hfdata->hf_audio_cards = NULL;
-     }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0020-bluetooth-Handle-CardAdded-signal.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0020-bluetooth-Handle-CardAdded-signal.patch
deleted file mode 100644 (file)
index f3aaf33..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Thu, 11 Jul 2013 11:47:37 -0300
-Subject: bluetooth: Handle CardAdded signal
-
-Change-Id: I695b97e26ce369d76503980c73fc3849252b4c91
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 18 ++++++++++++++++++
- 1 file changed, 18 insertions(+)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index 97e0fa8..be20257 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -411,6 +411,24 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *da
-             }
-         }
-+    } else if (dbus_message_is_signal(m, "org.ofono.HandsfreeAudioManager", "CardAdded")) {
-+        const char *p;
-+        DBusMessageIter arg_i, props_i;
-+
-+        if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oa{sv}")) {
-+            pa_log_error("Failed to parse org.ofono.HandsfreeAudioManager.CardAdded");
-+            goto fail;
-+        }
-+
-+        dbus_message_iter_get_basic(&arg_i, &p);
-+
-+        pa_assert_se(dbus_message_iter_next(&arg_i));
-+        pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_ARRAY);
-+
-+        dbus_message_iter_recurse(&arg_i, &props_i);
-+
-+        hf_audio_agent_card_found(hfdata, p, &props_i);
-+
-     }
- fail:
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0021-bluetooth-Handle-CardRemoved-signal.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0021-bluetooth-Handle-CardRemoved-signal.patch
deleted file mode 100644 (file)
index fbd766e..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Thu, 11 Jul 2013 12:53:10 -0300
-Subject: bluetooth: Handle CardRemoved signal
-
-Change-Id: I41083b3b5d8a318927dcdb373e871032c3f52748
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 23 +++++++++++++++++++++++
- 1 file changed, 23 insertions(+)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index be20257..ee158af 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -429,6 +429,29 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *da
-         hf_audio_agent_card_found(hfdata, p, &props_i);
-+    } else if (dbus_message_is_signal(m, "org.ofono.HandsfreeAudioManager", "CardRemoved")) {
-+        const char *p;
-+        hf_audio_card *hfac;
-+        bool old_any_connected;
-+
-+        if (!dbus_message_get_args(m, &err, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_INVALID)) {
-+            pa_log_error("Failed to parse org.ofono.HandsfreeAudioManager.CardRemoved: %s", err.message);
-+            goto fail;
-+        }
-+
-+        if ((hfac = pa_hashmap_remove(hfdata->hf_audio_cards, p)) != NULL) {
-+            old_any_connected = pa_bluetooth_device_any_transport_connected(hfac->transport->device);
-+
-+            hfac->transport->state = PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED;
-+            hfac->transport->device->transports[hfac->transport->profile] = NULL;
-+            pa_hook_fire(pa_bluetooth_discovery_hook(hfdata->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED), hfac->transport);
-+
-+            if (old_any_connected != pa_bluetooth_device_any_transport_connected(hfac->transport->device)) {
-+                pa_hook_fire(pa_bluetooth_discovery_hook(hfdata->discovery, PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED), hfac->transport->device);
-+            }
-+
-+            hf_audio_card_free(hfac);
-+        }
-     }
- fail:
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0022-bluetooth-Implement-org.ofono.HandsfreeAudioAgent.Ne.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0022-bluetooth-Implement-org.ofono.HandsfreeAudioAgent.Ne.patch
deleted file mode 100644 (file)
index 4ad62dc..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Thu, 11 Jul 2013 13:23:31 -0300
-Subject: bluetooth: Implement org.ofono.HandsfreeAudioAgent.NewConnection()
-
-Change-Id: Idaff2e3a96ce83e7ee6f961543273429b044be8e
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 29 +++++++++++++++++++++++++++--
- 1 file changed, 27 insertions(+), 2 deletions(-)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index ee158af..ba0acaf 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -491,7 +491,10 @@ static DBusMessage *hf_audio_agent_release(DBusConnection *c, DBusMessage *m, vo
- static DBusMessage *hf_audio_agent_new_connection(DBusConnection *c, DBusMessage *m, void *data) {
-     DBusMessage *r;
--    const char *sender;
-+    const char *sender, *card;
-+    int fd;
-+    uint8_t codec;
-+    hf_audio_card *hfac;
-     hf_audio_agent_data *hfdata = data;
-     pa_assert(hfdata);
-@@ -502,7 +505,29 @@ static DBusMessage *hf_audio_agent_new_connection(DBusConnection *c, DBusMessage
-         return r;
-     }
--    r = dbus_message_new_error(m, "org.ofono.Error.NotImplemented", "Operation is not implemented");
-+    if (dbus_message_get_args(m, NULL,
-+                              DBUS_TYPE_OBJECT_PATH, &card,
-+                              DBUS_TYPE_UNIX_FD, &fd,
-+                              DBUS_TYPE_BYTE, &codec,
-+                              DBUS_TYPE_INVALID) == FALSE) {
-+        pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.InvalidArguments", "Invalid arguments in method call"));
-+        return r;
-+    }
-+
-+    if ( !(hfac = pa_hashmap_get(hfdata->hf_audio_cards, card)) ) {
-+        pa_log_warn("New audio connection on unknown card %s (fd=%d, codec=%d)", card, fd, codec);
-+        pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.InvalidArguments", "Unknown card"));
-+        return r;
-+    } else
-+        pa_log_debug("New audio connection on card %s (fd=%d, codec=%d)", card, fd, codec);
-+
-+    hfac->fd = fd;
-+    hfac->codec = codec;
-+    hfac->transport->state = PA_BLUETOOTH_TRANSPORT_STATE_PLAYING;
-+    pa_hook_fire(pa_bluetooth_discovery_hook(hfdata->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED), hfac->transport);
-+
-+    pa_assert_se(r = dbus_message_new_method_return(m));
-+
-     return r;
- }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0023-bluetooth-Fix-not-handle-fd-in-DEFER_SETUP-state.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0023-bluetooth-Fix-not-handle-fd-in-DEFER_SETUP-state.patch
deleted file mode 100644 (file)
index 587fce6..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-Date: Fri, 23 Aug 2013 12:56:40 +0300
-Subject: bluetooth: Fix not handle fd in DEFER_SETUP state
-
-The fd passed over NewConnection is in DEFER_SETUP and need to be read to
-be accept otherwise it wont work.
-
-Change-Id: I2f6df033d3c1602064a39bb40a5bbd60e014c8f7
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 14 ++++++++++++--
- 1 file changed, 12 insertions(+), 2 deletions(-)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index ba0acaf..90d1348 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -23,6 +23,8 @@
- #include <config.h>
- #endif
-+#include <errno.h>
-+
- #include <pulsecore/core-util.h>
- #include <pulsecore/dbus-shared.h>
- #include <pulsecore/shared.h>
-@@ -518,8 +520,16 @@ static DBusMessage *hf_audio_agent_new_connection(DBusConnection *c, DBusMessage
-         pa_log_warn("New audio connection on unknown card %s (fd=%d, codec=%d)", card, fd, codec);
-         pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.InvalidArguments", "Unknown card"));
-         return r;
--    } else
--        pa_log_debug("New audio connection on card %s (fd=%d, codec=%d)", card, fd, codec);
-+    }
-+
-+    pa_log_debug("New audio connection on card %s (fd=%d, codec=%d)", card, fd, codec);
-+
-+    /* Do the socket defered setup */
-+    if (recv(fd, NULL, 0, 0) < 0) {
-+        const char *strerr = strerror(errno);
-+        pa_log_warn("Defered setup failed: %d (%s)", errno, strerr);
-+        pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.InvalidArguments", strerr));
-+    }
-     hfac->fd = fd;
-     hfac->codec = codec;
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0024-bluetooth-Suspend-sink-source-on-HFP-s-stream-HUP.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0024-bluetooth-Suspend-sink-source-on-HFP-s-stream-HUP.patch
deleted file mode 100644 (file)
index 5858d67..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-From: =?utf-8?q?Jo=C3=A3o_Paulo_Rechi_Vita?= <jprvita@openbossa.org>
-Date: Wed, 27 Mar 2013 01:43:42 -0300
-Subject: bluetooth: Suspend sink/source on HFP's stream HUP
-
-When the Audio Connection is disconnected the sink and source should be
-suspended.
-
-Change-Id: Ifedd5e7fe70ee74e509b82270ce84aba762f2412
----
- src/modules/bluetooth/module-bluez5-device.c | 17 ++++++++++++++---
- 1 file changed, 14 insertions(+), 3 deletions(-)
-
-diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
-index b511b92..ae5ec1d 100644
---- a/src/modules/bluetooth/module-bluez5-device.c
-+++ b/src/modules/bluetooth/module-bluez5-device.c
-@@ -74,6 +74,7 @@ static const char* const valid_modargs[] = {
- enum {
-     BLUETOOTH_MESSAGE_IO_THREAD_FAILED,
-+    BLUETOOTH_MESSAGE_TRANSPORT_STATE_CHANGED,
-     BLUETOOTH_MESSAGE_MAX
- };
-@@ -1427,6 +1428,12 @@ io_fail:
-         pending_read_bytes = 0;
-         writable = false;
-+        if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
-+            u->transport->state = PA_BLUETOOTH_TRANSPORT_STATE_IDLE;
-+            pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u->msg), BLUETOOTH_MESSAGE_TRANSPORT_STATE_CHANGED, u, 0,
-+                              NULL, NULL);
-+        }
-+
-         teardown_stream(u);
-     }
-@@ -1994,15 +2001,19 @@ static pa_hook_result_t transport_state_changed_cb(pa_bluetooth_discovery *y, pa
- /* Run from main thread context */
- static int device_process_msg(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
--    struct bluetooth_msg *u = BLUETOOTH_MSG(obj);
-+    struct bluetooth_msg *b = BLUETOOTH_MSG(obj);
-+    struct userdata *u = data;
-     switch (code) {
-+        case BLUETOOTH_MESSAGE_TRANSPORT_STATE_CHANGED:
-+            handle_transport_state_change(u, u->transport);
-+            break;
-         case BLUETOOTH_MESSAGE_IO_THREAD_FAILED:
--            if (u->card->module->unload_requested)
-+            if (b->card->module->unload_requested)
-                 break;
-             pa_log_debug("Switching the profile to off due to IO thread failure.");
--            pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false) >= 0);
-+            pa_assert_se(pa_card_set_profile(b->card, "off", false) >= 0);
-             break;
-     }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0025-bluetooth-Implement-transport-release-for-hf_audio_a.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0025-bluetooth-Implement-transport-release-for-hf_audio_a.patch
deleted file mode 100644 (file)
index b557ea5..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-Date: Fri, 23 Aug 2013 19:19:34 +0300
-Subject: bluetooth: Implement transport release for hf_audio_agent transports
-
-Change-Id: I496b3ab1c2f8e347c41262818ec3b9a35ed7262e
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index 90d1348..a0474df 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -153,6 +153,13 @@ static int hf_audio_agent_transport_acquire(pa_bluetooth_transport *t, bool opti
- }
- static void hf_audio_agent_transport_release(pa_bluetooth_transport *t) {
-+    hf_audio_agent_data *hfdata = t->userdata;
-+    hf_audio_card *hfac = pa_hashmap_get(hfdata->hf_audio_cards, t->path);
-+
-+    if (hfac) {
-+        shutdown(hfac->fd, SHUT_RDWR);
-+        hfac->fd = -1;
-+    }
- }
- static void hf_audio_agent_card_found(hf_audio_agent_data *hfdata, const char *path, DBusMessageIter *props_i) {
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0026-bluetooth-Fixes-HFP-audio-transfer-when-initiator.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0026-bluetooth-Fixes-HFP-audio-transfer-when-initiator.patch
deleted file mode 100644 (file)
index 4dd9742..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-Date: Fri, 23 Aug 2013 19:44:23 +0300
-Subject: bluetooth: Fixes HFP audio transfer when initiator
-
-This makes sure org.ofono.HandsfreeAudioCard.Connect is called regardless
-of the optional flag and also makes sure to update the profile state
-whenever SCO is disconnected.
-
-Change-Id: I4400753333f14a2381eb75d5b62d2ea51d1c7139
----
- src/modules/bluetooth/hfaudioagent-ofono.c   |  2 +-
- src/modules/bluetooth/module-bluez5-device.c | 14 +++++++-------
- 2 files changed, 8 insertions(+), 8 deletions(-)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index a0474df..59eafdb 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -126,7 +126,7 @@ static int hf_audio_agent_transport_acquire(pa_bluetooth_transport *t, bool opti
-     hf_audio_agent_data *hfdata = t->userdata;
-     hf_audio_card *hfac = pa_hashmap_get(hfdata->hf_audio_cards, t->path);
--    if (!optional) {
-+    if (hfac->fd < 0) {
-         DBusMessage *m;
-         pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.ofono.HandsfreeAudioCard", "Connect"));
-diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
-index ae5ec1d..39fa5d0 100644
---- a/src/modules/bluetooth/module-bluez5-device.c
-+++ b/src/modules/bluetooth/module-bluez5-device.c
-@@ -768,6 +768,12 @@ static void transport_release(struct userdata *u) {
-     u->transport_acquired = false;
-+    if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
-+        u->transport->state = PA_BLUETOOTH_TRANSPORT_STATE_IDLE;
-+        pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u->msg), BLUETOOTH_MESSAGE_TRANSPORT_STATE_CHANGED, u, 0,
-+                              NULL, NULL);
-+    }
-+
-     teardown_stream(u);
- }
-@@ -1428,13 +1434,7 @@ io_fail:
-         pending_read_bytes = 0;
-         writable = false;
--        if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
--            u->transport->state = PA_BLUETOOTH_TRANSPORT_STATE_IDLE;
--            pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u->msg), BLUETOOTH_MESSAGE_TRANSPORT_STATE_CHANGED, u, 0,
--                              NULL, NULL);
--        }
--
--        teardown_stream(u);
-+        transport_release(u);
-     }
- fail:
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0027-bluetooth-Set-off-profile-as-default-for-newly-creat.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0027-bluetooth-Set-off-profile-as-default-for-newly-creat.patch
deleted file mode 100644 (file)
index cce0497..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-Date: Mon, 16 Sep 2013 15:10:51 +0300
-Subject: bluetooth: Set 'off' profile as default for newly create cards
-
-This makes sure that pa_card_new doesn't select one profile based on
-priority which may conflict with audio policy.
-
-Change-Id: Ifa5ad111d0c9f58701f93bcfd85b70d1f096efac
----
- src/modules/bluetooth/module-bluez4-device.c | 1 +
- src/modules/bluetooth/module-bluez5-device.c | 1 +
- 2 files changed, 2 insertions(+)
-
-diff --git a/src/modules/bluetooth/module-bluez4-device.c b/src/modules/bluetooth/module-bluez4-device.c
-index 83e603f..b0b12f8 100644
---- a/src/modules/bluetooth/module-bluez4-device.c
-+++ b/src/modules/bluetooth/module-bluez4-device.c
-@@ -2295,6 +2295,7 @@ static int add_card(struct userdata *u) {
-     d = PA_CARD_PROFILE_DATA(p);
-     *d = PA_BLUEZ4_PROFILE_OFF;
-     pa_hashmap_put(data.profiles, p->name, p);
-+    pa_card_new_data_set_profile(&data, "off");
-     if ((default_profile = pa_modargs_get_value(u->modargs, "profile", NULL))) {
-         if (pa_hashmap_get(data.profiles, default_profile))
-diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
-index 39fa5d0..a0776c8 100644
---- a/src/modules/bluetooth/module-bluez5-device.c
-+++ b/src/modules/bluetooth/module-bluez5-device.c
-@@ -1888,6 +1888,7 @@ static int add_card(struct userdata *u) {
-     p = PA_CARD_PROFILE_DATA(cp);
-     *p = PA_BLUETOOTH_PROFILE_OFF;
-     pa_hashmap_put(data.profiles, cp->name, cp);
-+    pa_card_new_data_set_profile(&data, "off");
-     u->card = pa_card_new(u->core, &data);
-     pa_card_new_data_done(&data);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0028-fix-ofono-and-pulseaudio-starting-order-assert.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0028-fix-ofono-and-pulseaudio-starting-order-assert.patch
deleted file mode 100644 (file)
index db44a2e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Thu, 2 Jan 2014 15:37:02 +0200
-Subject: fix ofono and pulseaudio starting order assert
-
-Change-Id: I743c6e1fb5c65cc0702f073d6c2beb4e6868d7bb
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 6 ++----
- 1 file changed, 2 insertions(+), 4 deletions(-)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index 59eafdb..7f93c6b 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -403,10 +403,8 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *da
-             if (old_owner && *old_owner) {
-                 pa_log_debug("oFono disappeared");
--                if (hfdata->hf_audio_cards) {
--                    pa_hashmap_free(hfdata->hf_audio_cards);
--                    hfdata->hf_audio_cards = NULL;
--                }
-+                if (hfdata->hf_audio_cards)
-+                    pa_hashmap_remove_all(hfdata->hf_audio_cards);
-                 if(hfdata->ofono_bus_id) {
-                     pa_xfree(hfdata->ofono_bus_id);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0029-hfp-do-safe-strcmp-in-dbus-handler.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0029-hfp-do-safe-strcmp-in-dbus-handler.patch
deleted file mode 100644 (file)
index 8402ffa..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Mon, 30 Dec 2013 18:03:18 +0200
-Subject: hfp do safe strcmp in dbus handler
-
-Change-Id: I4ba64d22b2b807530263b5f274cd89f208c675ac
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/bluetooth/hfaudioagent-ofono.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
-index 7f93c6b..2ac8a82 100644
---- a/src/modules/bluetooth/hfaudioagent-ofono.c
-+++ b/src/modules/bluetooth/hfaudioagent-ofono.c
-@@ -381,7 +381,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *da
-     pa_assert(hfdata);
-     sender = dbus_message_get_sender(m);
--    if (!pa_safe_streq(hfdata->ofono_bus_id, sender) && !pa_streq("org.freedesktop.DBus", sender))
-+    if (!pa_safe_streq(hfdata->ofono_bus_id, sender) && !pa_safe_streq("org.freedesktop.DBus", sender))
-         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-     dbus_error_init(&err);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0030-add-parameter-to-define-key-used-in-stream-restore.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0030-add-parameter-to-define-key-used-in-stream-restore.patch
deleted file mode 100644 (file)
index 0773d40..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Thu, 5 Sep 2013 12:21:19 +0300
-Subject: add parameter to define key used in stream restore.
-
-It is possible now to use preferred_stream_group
-command line parameter when loading module stream
-restore. This key will be searched from the stream's
-proplist and if found it is used as key when
-restoring the volumes and other values. There's also
-special value media.role.within.appication.name you
-can use to enable restoring stream roles within
-application. So different streams with different
-roles within application will save their volumes.
-If the preferred stream group parameter is left out
-module stream restore will fallback to old default
-functionality.
-
-Change-Id: I636f47b43476f3d4cd6c14244eafcd050683bb69
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/module-stream-restore.c | 34 +++++++++++++---------
- src/pulsecore/proplist-util.c       | 58 +++++++++++++++++++++++++++++++++++++
- src/pulsecore/proplist-util.h       |  1 +
- 3 files changed, 80 insertions(+), 13 deletions(-)
-
-diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
-index 9689e79..68968c9 100644
---- a/src/modules/module-stream-restore.c
-+++ b/src/modules/module-stream-restore.c
-@@ -70,7 +70,8 @@ PA_MODULE_USAGE(
-         "restore_muted=<Save/restore muted states?> "
-         "on_hotplug=<When new device becomes available, recheck streams?> "
-         "on_rescue=<When device becomes unavailable, recheck streams?> "
--        "fallback_table=<filename>");
-+        "fallback_table=<filename>"
-+        "preferred_stream_group=<prefer certain stream group in restore?> ");
- #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
- #define IDENTIFICATION_PROPERTY "module-stream-restore.id"
-@@ -87,6 +88,7 @@ static const char* const valid_modargs[] = {
-     "on_hotplug",
-     "on_rescue",
-     "fallback_table",
-+    "preferred_stream_group",
-     NULL
- };
-@@ -112,6 +114,7 @@ struct userdata {
-     bool restore_muted:1;
-     bool on_hotplug:1;
-     bool on_rescue:1;
-+    char *preferred_stream_group;
-     pa_native_protocol *protocol;
-     pa_idxset *subscribed;
-@@ -1277,7 +1280,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
-         if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx)))
-             return;
--        if (!(name = pa_proplist_get_stream_group(sink_input->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
-+        if (!(name = pa_proplist_get_stream_group_extended(sink_input->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-             return;
-         if ((old = entry_read(u, name))) {
-@@ -1327,7 +1330,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
-         if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx)))
-             return;
--        if (!(name = pa_proplist_get_stream_group(source_output->proplist, "source-output", IDENTIFICATION_PROPERTY)))
-+        if (!(name = pa_proplist_get_stream_group_extended(source_output->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-             return;
-         if ((old = entry_read(u, name))) {
-@@ -1420,7 +1423,7 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n
-     pa_assert(u);
-     pa_assert(u->restore_device);
--    if (!(name = pa_proplist_get_stream_group(new_data->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
-+    if (!(name = pa_proplist_get_stream_group_extended(new_data->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-         return PA_HOOK_OK;
-     if (new_data->sink)
-@@ -1462,7 +1465,7 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
-     pa_assert(u);
-     pa_assert(u->restore_volume || u->restore_muted);
--    if (!(name = pa_proplist_get_stream_group(new_data->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
-+    if (!(name = pa_proplist_get_stream_group_extended(new_data->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-         return PA_HOOK_OK;
-     if ((e = entry_read(u, name))) {
-@@ -1516,7 +1519,7 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou
-     if (new_data->direct_on_input)
-         return PA_HOOK_OK;
--    if (!(name = pa_proplist_get_stream_group(new_data->proplist, "source-output", IDENTIFICATION_PROPERTY)))
-+    if (!(name = pa_proplist_get_stream_group_extended(new_data->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-         return PA_HOOK_OK;
-     if (new_data->source)
-@@ -1559,7 +1562,7 @@ static pa_hook_result_t source_output_fixate_hook_callback(pa_core *c, pa_source
-     pa_assert(u);
-     pa_assert(u->restore_volume || u->restore_muted);
--    if (!(name = pa_proplist_get_stream_group(new_data->proplist, "source-output", IDENTIFICATION_PROPERTY)))
-+    if (!(name = pa_proplist_get_stream_group_extended(new_data->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-         return PA_HOOK_OK;
-     if ((e = entry_read(u, name))) {
-@@ -1631,7 +1634,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct
-         if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si)))
-             continue;
--        if (!(name = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
-+        if (!(name = pa_proplist_get_stream_group_extended(si->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-             continue;
-         if ((e = entry_read(u, name))) {
-@@ -1679,7 +1682,7 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
-         if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so)))
-             continue;
--        if (!(name = pa_proplist_get_stream_group(so->proplist, "source-output", IDENTIFICATION_PROPERTY)))
-+        if (!(name = pa_proplist_get_stream_group_extended(so->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-             continue;
-         if ((e = entry_read(u, name))) {
-@@ -1715,7 +1718,7 @@ static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, str
-         if (!si->sink)
-             continue;
--        if (!(name = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
-+        if (!(name = pa_proplist_get_stream_group_extended(si->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-             continue;
-         if ((e = entry_read(u, name))) {
-@@ -1761,7 +1764,7 @@ static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *sourc
-         if (!so->source)
-             continue;
--        if (!(name = pa_proplist_get_stream_group(so->proplist, "source-output", IDENTIFICATION_PROPERTY)))
-+        if (!(name = pa_proplist_get_stream_group_extended(so->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-             continue;
-         if ((e = entry_read(u, name))) {
-@@ -1880,7 +1883,7 @@ static void entry_apply(struct userdata *u, const char *name, struct entry *e) {
-         char *n;
-         pa_sink *s;
--        if (!(n = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
-+        if (!(n = pa_proplist_get_stream_group_extended(si->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-             continue;
-         if (!pa_streq(name, n)) {
-@@ -1928,7 +1931,7 @@ static void entry_apply(struct userdata *u, const char *name, struct entry *e) {
-         char *n;
-         pa_source *s;
--        if (!(n = pa_proplist_get_stream_group(so->proplist, "source-output", IDENTIFICATION_PROPERTY)))
-+        if (!(n = pa_proplist_get_stream_group_extended(so->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
-             continue;
-         if (!pa_streq(name, n)) {
-@@ -2411,6 +2414,8 @@ int pa__init(pa_module*m) {
-     u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u);
-+    u->preferred_stream_group = pa_xstrdup(pa_modargs_get_value(ma, "preferred_stream_group", NULL));
-+
-     if (restore_device) {
-         /* A little bit earlier than module-intended-roles ... */
-         u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_new_hook_callback, u);
-@@ -2554,5 +2559,8 @@ void pa__done(pa_module*m) {
-     if (u->subscribed)
-         pa_idxset_free(u->subscribed, NULL);
-+    if (u->preferred_stream_group)
-+        pa_xfree(u->preferred_stream_group);
-+
-     pa_xfree(u);
- }
-diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c
-index 473290f..0a8dbca 100644
---- a/src/pulsecore/proplist-util.c
-+++ b/src/pulsecore/proplist-util.c
-@@ -274,3 +274,61 @@ char *pa_proplist_get_stream_group(pa_proplist *p, const char *prefix, const cha
-     return t;
- }
-+
-+char *pa_proplist_get_stream_group_extended(pa_proplist *p, const char *prefix, const char *cache, const char *preferred_stream_group) {
-+    const char *r = NULL;
-+    const char *q = NULL;
-+    char *t;
-+
-+    if (!p)
-+        return NULL;
-+
-+    if (cache && (r = pa_proplist_gets(p, cache)))
-+        return pa_xstrdup(r);
-+
-+    if (!prefix)
-+        prefix = "stream";
-+
-+    /* try first to get the preferred stream group, then fallback to hard coded order */
-+    if (preferred_stream_group) {
-+        if (!strcmp(preferred_stream_group, "media.role.within.application.name")) {
-+          if ((r = pa_proplist_gets(p, PA_PROP_APPLICATION_NAME)) &&
-+              (q = pa_proplist_gets(p, PA_PROP_MEDIA_ROLE))) {
-+                    t = pa_sprintf_malloc("%s-by-media-role-within-application-name:%s-%s", prefix, q, r);
-+          } else {
-+              /* make r NULL to be able to fallback to "standard" stream restore code */
-+                r = NULL;
-+          }
-+      }
-+      else if ((r = pa_proplist_gets(p, preferred_stream_group))) {
-+            if (!strcmp(preferred_stream_group, PA_PROP_MEDIA_ROLE))
-+                t = pa_sprintf_malloc("%s-by-media-role:%s", prefix, r);
-+          else if (!strcmp(preferred_stream_group, PA_PROP_APPLICATION_ID))
-+                t = pa_sprintf_malloc("%s-by-application-id:%s", prefix, r);
-+            else if (!strcmp(preferred_stream_group, PA_PROP_APPLICATION_NAME))
-+                t = pa_sprintf_malloc("%s-by-application-name:%s", prefix, r);
-+            else if (!strcmp(preferred_stream_group, PA_PROP_MEDIA_NAME))
-+              t = pa_sprintf_malloc("%s-by-media-name:%s", prefix, r);
-+            else
-+                t = pa_sprintf_malloc("%s-fallback:%s", prefix, r);
-+        }
-+    }
-+
-+    if (!r) {
-+        if ((r = pa_proplist_gets(p, PA_PROP_MEDIA_ROLE)))
-+            t = pa_sprintf_malloc("%s-by-media-role:%s", prefix, r);
-+        else if ((r = pa_proplist_gets(p, PA_PROP_APPLICATION_ID)))
-+            t = pa_sprintf_malloc("%s-by-application-id:%s", prefix, r);
-+        else if ((r = pa_proplist_gets(p, PA_PROP_APPLICATION_NAME)))
-+            t = pa_sprintf_malloc("%s-by-application-name:%s", prefix, r);
-+        else if ((r = pa_proplist_gets(p, PA_PROP_MEDIA_NAME)))
-+            t = pa_sprintf_malloc("%s-by-media-name:%s", prefix, r);
-+        else
-+            t = pa_sprintf_malloc("%s-fallback:%s", prefix, r);
-+    }
-+
-+    if (cache)
-+        pa_proplist_sets(p, cache, t);
-+
-+    return t;
-+}
-diff --git a/src/pulsecore/proplist-util.h b/src/pulsecore/proplist-util.h
-index 3d08776..47bdb57 100644
---- a/src/pulsecore/proplist-util.h
-+++ b/src/pulsecore/proplist-util.h
-@@ -26,5 +26,6 @@
- void pa_init_proplist(pa_proplist *p);
- char *pa_proplist_get_stream_group(pa_proplist *pl, const char *prefix, const char *cache);
-+char *pa_proplist_get_stream_group_extended(pa_proplist *p, const char *prefix, const char *cache, const char *preferred_stream_group);
- #endif
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0031-increase-alsa-rewind-safeguard.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0031-increase-alsa-rewind-safeguard.patch
deleted file mode 100644 (file)
index eac1811..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Mon, 28 Apr 2014 11:26:15 +0300
-Subject: increase alsa rewind safeguard
-
-In some devices alsa drivers behaves badly
-if pulseaudio rewind safeguard is too small.
-This is not fixing the driver issues, but is
-a workaround to give time (1.33ms->5ms) for
-user space processing so that alsa is not
-getting into this weird state. This could be
-also helped by running pulseaudio in realtime.
-This is of course increasing the volume setting
-latency, but should leave it still quite
-responsive.
-
-Change-Id: Iecdf879bf8ba58e991808d2dc382def05de36ec9
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/alsa/alsa-sink.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
-index ccf1137..5a41cf6 100644
---- a/src/modules/alsa/alsa-sink.c
-+++ b/src/modules/alsa/alsa-sink.c
-@@ -87,8 +87,13 @@
- #define VOLUME_ACCURACY (PA_VOLUME_NORM/100)  /* don't require volume adjustments to be perfectly correct. don't necessarily extend granularity in software unless the differences get greater than this level */
-+#if 0
- #define DEFAULT_REWIND_SAFEGUARD_BYTES (256U) /* 1.33ms @48kHz, we'll never rewind less than this */
- #define DEFAULT_REWIND_SAFEGUARD_USEC (1330) /* 1.33ms, depending on channels/rate/sample we may rewind more than 256 above */
-+#endif
-+
-+#define DEFAULT_REWIND_SAFEGUARD_BYTES (1024U) /* increase safeguard 4x */
-+#define DEFAULT_REWIND_SAFEGUARD_USEC (5000) /* increase safeguard ~4x */
- struct userdata {
-     pa_core *core;
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0032-fix-for-profile-change-prototype-in-bluez5-patch.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0032-fix-for-profile-change-prototype-in-bluez5-patch.patch
deleted file mode 100644 (file)
index 646694a..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Tue, 11 Mar 2014 12:23:09 +0200
-Subject: fix for profile change prototype in bluez5 patch
-
-Change-Id: I2361c4eca82e6ac4a8f94e9f9c97f09cb6648049
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/bluetooth/module-bluez5-device.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
-index a0776c8..790dcf1 100644
---- a/src/modules/bluetooth/module-bluez5-device.c
-+++ b/src/modules/bluetooth/module-bluez5-device.c
-@@ -2014,7 +2014,7 @@ static int device_process_msg(pa_msgobject *obj, int code, void *data, int64_t o
-                 break;
-             pa_log_debug("Switching the profile to off due to IO thread failure.");
--            pa_assert_se(pa_card_set_profile(b->card, "off", false) >= 0);
-+            pa_assert_se(pa_card_set_profile(b->card, pa_hashmap_get(u->card->profiles, "off"), false) >= 0);
-             break;
-     }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0033-changes-to-pa-simple-api-samsung.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0033-changes-to-pa-simple-api-samsung.patch
deleted file mode 100644 (file)
index e041892..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-From: "vivian,zhang" <vivian.zhang@intel.com>
-Date: Tue, 18 Jun 2013 16:10:15 +0800
-Subject: changes to pa simple api - samsung
-
-Change-Id: I997c02217a8dc14524480164aa0baeea901c7b4e
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/Makefile.am    |   4 +-
- src/map-file       |   6 ++
- src/pulse/simple.c | 288 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/pulse/simple.h |  28 ++++++
- 4 files changed, 324 insertions(+), 2 deletions(-)
-
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 2edce5f..5ec8609 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -824,7 +824,7 @@ libpulse_la_SOURCES = \
-               pulse/volume.c pulse/volume.h \
-               pulse/xmalloc.c pulse/xmalloc.h
--libpulse_la_CFLAGS = $(AM_CFLAGS) $(LIBJSON_CFLAGS)
-+libpulse_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(LIBJSON_CFLAGS)
- libpulse_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) $(LTLIBICONV) $(LIBJSON_LIBS) libpulsecommon-@PA_MAJORMINOR@.la
- libpulse_la_LDFLAGS = $(AM_LDFLAGS) $(VERSIONING_LDFLAGS) -version-info $(LIBPULSE_VERSION_INFO)
-@@ -834,7 +834,7 @@ libpulse_la_LIBADD += $(DBUS_LIBS)
- endif
- libpulse_simple_la_SOURCES = pulse/simple.c pulse/simple.h
--libpulse_simple_la_CFLAGS = $(AM_CFLAGS)
-+libpulse_simple_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
- libpulse_simple_la_LIBADD = $(AM_LIBADD) libpulse.la libpulsecommon-@PA_MAJORMINOR@.la
- libpulse_simple_la_LDFLAGS = $(AM_LDFLAGS) $(VERSIONING_LDFLAGS) -version-info $(LIBPULSE_SIMPLE_VERSION_INFO)
-diff --git a/src/map-file b/src/map-file
-index 7dbcd00..95364ae 100644
---- a/src/map-file
-+++ b/src/map-file
-@@ -282,11 +282,17 @@ pa_signal_new;
- pa_signal_set_destroy;
- pa_simple_drain;
- pa_simple_flush;
-+pa_simple_mute;
- pa_simple_free;
- pa_simple_get_latency;
- pa_simple_new;
-+pa_simple_new_proplist;
- pa_simple_read;
- pa_simple_write;
-+pa_simple_set_volume;
-+pa_simple_get_stream_index;
-+pa_simple_cork;
-+pa_simple_is_corked;
- pa_stream_begin_write;
- pa_stream_cancel_write;
- pa_stream_connect_playback;
-diff --git a/src/pulse/simple.c b/src/pulse/simple.c
-index 1891131..9109ffa 100644
---- a/src/pulse/simple.c
-+++ b/src/pulse/simple.c
-@@ -32,10 +32,12 @@
- #include <pulse/thread-mainloop.h>
- #include <pulse/xmalloc.h>
-+#include <pulsecore/native-common.h>
- #include <pulsecore/log.h>
- #include <pulsecore/macro.h>
- #include "simple.h"
-+#include "internal.h"
- struct pa_simple {
-     pa_threaded_mainloop *mainloop;
-@@ -102,6 +104,24 @@ static void context_state_cb(pa_context *c, void *userdata) {
-     }
- }
-+static void stream_success_context_cb(pa_stream *s, int success, void *userdata) {
-+      pa_simple *p = userdata;
-+      pa_assert(s);
-+      pa_assert(p);
-+
-+    p->operation_success = success;
-+    pa_threaded_mainloop_signal(p->mainloop, 0);
-+}
-+
-+static void success_context_cb(pa_context *c, int success, void *userdata) {
-+      pa_simple *p = userdata;
-+      pa_assert(c);
-+      pa_assert(p);
-+
-+    p->operation_success = success;
-+    pa_threaded_mainloop_signal(p->mainloop, 0);
-+}
-+
- static void stream_state_cb(pa_stream *s, void * userdata) {
-     pa_simple *p = userdata;
-     pa_assert(s);
-@@ -251,6 +271,122 @@ fail:
-     return NULL;
- }
-+pa_simple* pa_simple_new_proplist(
-+        const char *server,
-+        const char *name,
-+        pa_stream_direction_t dir,
-+        const char *dev,
-+        const char *stream_name,
-+        const pa_sample_spec *ss,
-+        const pa_channel_map *map,
-+        const pa_buffer_attr *attr,
-+        pa_proplist *proplist,
-+        int *rerror) {
-+
-+    pa_simple *p;
-+    int error = PA_ERR_INTERNAL, r;
-+
-+    CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL)
-+
-+    p = pa_xnew0(pa_simple, 1);
-+    p->direction = dir;
-+
-+    if (!(p->mainloop = pa_threaded_mainloop_new()))
-+        goto fail;
-+
-+    if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name)))
-+        goto fail;
-+
-+    pa_context_set_state_callback(p->context, context_state_cb, p);
-+
-+    if (pa_context_connect(p->context, server, 0, NULL) < 0) {
-+        error = pa_context_errno(p->context);
-+        goto fail;
-+    }
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+
-+    if (pa_threaded_mainloop_start(p->mainloop) < 0)
-+        goto unlock_and_fail;
-+
-+    for (;;) {
-+        pa_context_state_t state;
-+
-+        state = pa_context_get_state(p->context);
-+
-+        if (state == PA_CONTEXT_READY)
-+            break;
-+
-+        if (!PA_CONTEXT_IS_GOOD(state)) {
-+            error = pa_context_errno(p->context);
-+            goto unlock_and_fail;
-+        }
-+
-+        /* Wait until the context is ready */
-+        pa_threaded_mainloop_wait(p->mainloop);
-+    }
-+
-+    if (!(p->stream = pa_stream_new_with_proplist(p->context, stream_name, ss, map, proplist))) {
-+        error = pa_context_errno(p->context);
-+        goto unlock_and_fail;
-+    }
-+
-+    pa_stream_set_state_callback(p->stream, stream_state_cb, p);
-+    pa_stream_set_read_callback(p->stream, stream_request_cb, p);
-+    pa_stream_set_write_callback(p->stream, stream_request_cb, p);
-+    pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
-+
-+    if (dir == PA_STREAM_PLAYBACK)
-+        r = pa_stream_connect_playback(p->stream, dev, attr,
-+                                       PA_STREAM_INTERPOLATE_TIMING
-+                                       |PA_STREAM_ADJUST_LATENCY
-+                                       |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
-+    else
-+        r = pa_stream_connect_record(p->stream, dev, attr,
-+                                     PA_STREAM_INTERPOLATE_TIMING
-+                                     |PA_STREAM_ADJUST_LATENCY
-+                                     |PA_STREAM_AUTO_TIMING_UPDATE
-+                                     |PA_STREAM_START_CORKED);
-+
-+    if (r < 0) {
-+        error = pa_context_errno(p->context);
-+        goto unlock_and_fail;
-+    }
-+
-+    for (;;) {
-+        pa_stream_state_t state;
-+
-+        state = pa_stream_get_state(p->stream);
-+
-+        if (state == PA_STREAM_READY)
-+            break;
-+
-+        if (!PA_STREAM_IS_GOOD(state)) {
-+            error = pa_context_errno(p->context);
-+            goto unlock_and_fail;
-+        }
-+
-+        /* Wait until the stream is ready */
-+        pa_threaded_mainloop_wait(p->mainloop);
-+    }
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+    return p;
-+
-+unlock_and_fail:
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+fail:
-+    if (rerror)
-+        *rerror = error;
-+    pa_simple_free(p);
-+    return NULL;
-+}
- void pa_simple_free(pa_simple *s) {
-     pa_assert(s);
-@@ -452,6 +588,111 @@ unlock_and_fail:
-     return -1;
- }
-+int pa_simple_mute(pa_simple *p, int mute, int *rerror) {
-+    pa_operation *o = NULL;
-+    uint32_t idx;
-+
-+    pa_assert(p);
-+
-+    CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+    CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+
-+    CHECK_SUCCESS_GOTO(p, rerror, ((idx = pa_stream_get_index (p->stream)) != PA_INVALID_INDEX), unlock_and_fail);
-+
-+
-+    o = pa_context_set_sink_input_mute (p->context, idx, mute, success_context_cb, p);
-+    CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
-+
-+    p->operation_success = 0;
-+    while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
-+        pa_threaded_mainloop_wait(p->mainloop);
-+        CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+    }
-+    CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
-+
-+    pa_operation_unref(o);
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+    return 0;
-+
-+unlock_and_fail:
-+
-+    if (o) {
-+        pa_operation_cancel(o);
-+        pa_operation_unref(o);
-+    }
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+    return -1;
-+}
-+
-+int pa_simple_get_stream_index(pa_simple *p, unsigned int *idx, int *rerror) {
-+    pa_assert(p);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, idx != NULL, PA_ERR_INVALID, -1);
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+
-+    CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+
-+      *idx = pa_stream_get_index(p->stream);
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+    return 0;
-+
-+unlock_and_fail:
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+    return -1;
-+}
-+
-+int pa_simple_set_volume(pa_simple *p, int volume, int *rerror) {
-+    pa_operation *o = NULL;
-+    pa_stream *s = NULL;
-+    uint32_t idx;
-+    pa_cvolume cv;
-+
-+
-+    pa_assert(p);
-+
-+    CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, volume >= 0, PA_ERR_INVALID, -1);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, volume <= 65535, PA_ERR_INVALID, -1);
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+    CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+
-+    CHECK_SUCCESS_GOTO(p, rerror, ((idx = pa_stream_get_index (p->stream)) != PA_INVALID_INDEX), unlock_and_fail);
-+
-+    s = p->stream;
-+    pa_assert(s);
-+    pa_cvolume_set(&cv, s->sample_spec.channels, volume);
-+
-+    o = pa_context_set_sink_input_volume (p->context, idx, &cv, success_context_cb, p);
-+    CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
-+
-+    p->operation_success = 0;
-+    while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
-+        pa_threaded_mainloop_wait(p->mainloop);
-+        CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+    }
-+    CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
-+
-+    pa_operation_unref(o);
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+    return 0;
-+
-+unlock_and_fail:
-+
-+    if (o) {
-+        pa_operation_cancel(o);
-+        pa_operation_unref(o);
-+    }
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+    return -1;
-+}
- pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) {
-     pa_usec_t t;
-     int negative;
-@@ -481,3 +722,50 @@ unlock_and_fail:
-     pa_threaded_mainloop_unlock(p->mainloop);
-     return (pa_usec_t) -1;
- }
-+
-+int pa_simple_cork(pa_simple *p, int cork, int *rerror) {
-+    pa_operation *o = NULL;
-+
-+    pa_assert(p);
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+    CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+
-+    o = pa_stream_cork(p->stream, cork, stream_success_context_cb, p);
-+    CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
-+
-+    p->operation_success = 0;
-+    while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
-+        pa_threaded_mainloop_wait(p->mainloop);
-+        CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+    }
-+    CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
-+
-+    pa_operation_unref(o);
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+    return 0;
-+
-+unlock_and_fail:
-+
-+    if (o) {
-+        pa_operation_cancel(o);
-+        pa_operation_unref(o);
-+    }
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+    return -1;
-+}
-+
-+int pa_simple_is_corked(pa_simple *p) {
-+      int is_cork;
-+    pa_assert(p);
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+
-+    is_cork = pa_stream_is_corked(p->stream);
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+    return is_cork;
-+}
-diff --git a/src/pulse/simple.h b/src/pulse/simple.h
-index 54003ff..4f4a988 100644
---- a/src/pulse/simple.h
-+++ b/src/pulse/simple.h
-@@ -31,6 +31,7 @@
- #include <pulse/cdecl.h>
- #include <pulse/version.h>
-+#include <pulse/proplist.h>
- /** \page simple Simple API
-  *
-  * \section overv_sec Overview
-@@ -129,6 +130,19 @@ pa_simple* pa_simple_new(
-     int *error                          /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */
-     );
-+/** Create a new connection to the server with proplist */
-+pa_simple* pa_simple_new_proplist(
-+    const char *server,                 /**< Server name, or NULL for default */
-+    const char *name,                   /**< A descriptive name for this client (application name, ...) */
-+    pa_stream_direction_t dir,          /**< Open this stream for recording or playback? */
-+    const char *dev,                    /**< Sink (resp. source) name, or NULL for default */
-+    const char *stream_name,            /**< A descriptive name for this client (application name, song title, ...) */
-+    const pa_sample_spec *ss,           /**< The sample type to use */
-+    const pa_channel_map *map,          /**< The channel map to use, or NULL for default */
-+    const pa_buffer_attr *attr,         /**< Buffering attributes, or NULL for default */
-+    pa_proplist *proplist,    /**< Properties, or NULL for default */
-+    int *error                          /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */
-+    );
- /** Close and free the connection to the server. The connection object becomes invalid when this is called. */
- void pa_simple_free(pa_simple *s);
-@@ -155,6 +169,20 @@ pa_usec_t pa_simple_get_latency(pa_simple *s, int *error);
- /** Flush the playback or record buffer. This discards any audio in the buffer. */
- int pa_simple_flush(pa_simple *s, int *error);
-+/** Mute the playback stream */
-+int pa_simple_mute(pa_simple *p, int mute, int *rerror);
-+
-+/** Volume control the playback stream */
-+int pa_simple_set_volume(pa_simple *p, int volume, int *rerror);
-+
-+/** Get stream index */
-+int pa_simple_get_stream_index(pa_simple *p, unsigned int *idx, int *rerror);
-+
-+/** Cork on=1/off=0 stream */
-+int pa_simple_cork(pa_simple *p, int cork, int *rerror);
-+
-+/** Check whether stream is corked or not */
-+int pa_simple_is_corked(pa_simple *p);
- PA_C_DECL_END
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0034-add-support-for-samsung-power-management-samsung.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0034-add-support-for-samsung-power-management-samsung.patch
deleted file mode 100644 (file)
index 5d2380b..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-From: "vivian,zhang" <vivian.zhang@intel.com>
-Date: Tue, 18 Jun 2013 16:11:16 +0800
-Subject: add support for samsung power management - samsung
-
-Change-Id: Id76a3971e36c08773848fdf1ac1cc9a9200d7330
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- configure.ac                         |  12 +++
- src/Makefile.am                      |   3 +
- src/modules/module-suspend-on-idle.c | 179 ++++++++++++++++++++++++++++++++++-
- 3 files changed, 192 insertions(+), 2 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index a35918c..9a79b36 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -673,6 +673,18 @@ AS_IF([test "x$enable_samplerate" = "xyes" && test "x$HAVE_LIBSAMPLERATE" = "x0"
- AM_CONDITIONAL([HAVE_LIBSAMPLERATE], [test "x$HAVE_LIBSAMPLERATE" = x1])
- AS_IF([test "x$HAVE_LIBSAMPLERATE" = "x1"], AC_DEFINE([HAVE_LIBSAMPLERATE], 1, [Have libsamplerate?]))
-+#### samsung PM API support ####
-+
-+AC_ARG_ENABLE(pmlock, AC_HELP_STRING([--enable-pmlock], [using Samsung power management api]),
-+[
-+ case "${enableval}" in
-+     yes) USE_PM_LOCK=yes ;;
-+     no)  USE_PM_LOCK=no ;;
-+     *)   AC_MSG_ERROR(bad value ${enableval} for --enable-pmlock) ;;
-+ esac
-+ ],[USE_PM_LOCK=no])
-+AM_CONDITIONAL(USE_PM_LOCK, test "x$USE_PM_LOCK" = "xyes")
-+
- #### Database support ####
- AC_ARG_WITH([database],
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 5ec8609..12bb73e 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -1940,6 +1940,9 @@ module_suspend_on_idle_la_SOURCES = modules/module-suspend-on-idle.c
- module_suspend_on_idle_la_LDFLAGS = $(MODULE_LDFLAGS)
- module_suspend_on_idle_la_LIBADD = $(MODULE_LIBADD)
- module_suspend_on_idle_la_CFLAGS = $(AM_CFLAGS)
-+if USE_PM_LOCK
-+module_suspend_on_idle_la_CFLAGS += -DUSE_PM_LOCK
-+endif
- # echo-cancel module
- module_echo_cancel_la_SOURCES = \
-diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c
-index 15cbf95..8350917 100644
---- a/src/modules/module-suspend-on-idle.c
-+++ b/src/modules/module-suspend-on-idle.c
-@@ -34,7 +34,53 @@
- #include <pulsecore/modargs.h>
- #include <pulsecore/log.h>
-+#include <pulsecore/namereg.h>
- #include "module-suspend-on-idle-symdef.h"
-+//move to configure.ac
-+//#define USE_PM_LOCK /* Enable as default */
-+#ifdef USE_PM_LOCK
-+
-+#include <sys/types.h>
-+#include <sys/socket.h>
-+#include <sys/un.h>
-+#include <unistd.h>
-+#include <stdio.h>
-+#include <errno.h>
-+#include <linux/limits.h>
-+
-+#define SOCK_PATH                     "/tmp/pm_sock"
-+#define SHIFT_UNLOCK                  4
-+#define SHIFT_UNLOCK_PARAMETER                12
-+#define SHIFT_CHANGE_STATE            8
-+#define SHIFT_HOLD_KEY_BLOCK          16
-+#define SHIFT_CHANGE_TIMEOUT          20
-+#define TIMEOUT_RESET_BIT             0x80
-+
-+#define LCD_NORMAL      0x1   /**< NORMAL state */
-+#define LCD_DIM         0x2  /**< LCD dimming state */
-+#define LCD_OFF         0x4  /**< LCD off state */
-+#define SUSPEND         0x8  /**< Sleep state */
-+#define POWER_OFF       0x16  /**< Sleep state */
-+#define SETALL (LCD_DIM | LCD_OFF | LCD_NORMAL) /*< select all state - not supported yet */
-+
-+/* parameters for pm_lock_state() */
-+#define STAY_CUR_STATE  0x0
-+#define GOTO_STATE_NOW  0x1
-+#define HOLD_KEY_BLOCK  0x2
-+
-+/* paramters for pm_unlcok_state() - details are described at 162 line */
-+#define PM_SLEEP_MARGIN 0x0     /**< keep guard time for unlock */
-+#define PM_RESET_TIMER  0x1     /**< reset timer for unlock */
-+#define PM_KEEP_TIMER   0x2     /**< keep timer for unlock */
-+
-+struct pwr_msg {
-+      pid_t pid;
-+      unsigned int cond;
-+      unsigned int timeout;
-+      unsigned int timeout2;
-+};
-+
-+#endif /* USE_PM_LOCK */
- PA_MODULE_AUTHOR("Lennart Poettering");
- PA_MODULE_DESCRIPTION("When a sink/source is idle for too long, suspend it");
-@@ -47,6 +93,13 @@ static const char* const valid_modargs[] = {
-     NULL,
- };
-+#ifdef USE_PM_LOCK
-+#define PM_TYPE_SINK  0x01
-+#define PM_TYPE_SOURCE        0x02
-+
-+#define UPDATE_PM_LOCK(current,type)  (current |= type)
-+#define UPDATE_PM_UNLOCK(current,type)        (current &= ~type)
-+#endif /* USE_PM_LOCK */
- struct userdata {
-     pa_core *core;
-     pa_usec_t timeout;
-@@ -70,6 +123,9 @@ struct userdata {
-         *source_output_move_finish_slot,
-         *sink_input_state_changed_slot,
-         *source_output_state_changed_slot;
-+#ifdef USE_PM_LOCK
-+    uint32_t pm_state;
-+#endif /* USE_PM_LOCK */
- };
- struct device_info {
-@@ -80,10 +136,83 @@ struct device_info {
-     pa_time_event *time_event;
-     pa_usec_t timeout;
- };
-+#ifdef USE_PM_LOCK
-+
-+static int send_msg(unsigned int s_bits, unsigned int timeout, unsigned int timeout2)
-+{
-+      int rc = 0;
-+      int sock;
-+      struct pwr_msg p;
-+      struct sockaddr_un remote;
-+
-+      p.pid = getpid();
-+      p.cond = s_bits;
-+      p.timeout = timeout;
-+      p.timeout2 = timeout2;
-+
-+      sock = socket(AF_UNIX, SOCK_DGRAM, 0);
-+      if (sock == -1) {
-+              return -1;
-+      }
-+
-+      remote.sun_family = AF_UNIX;
-+      if(strlen(SOCK_PATH) >= sizeof(remote.sun_path)) {
-+              return -1;
-+      }
-+      strncpy(remote.sun_path, SOCK_PATH, sizeof(remote.sun_path));
-+
-+      rc = sendto(sock, (void *)&p, sizeof(p), 0, (struct sockaddr *)&remote,
-+                  sizeof(struct sockaddr_un));
-+
-+      close(sock);
-+      return rc;
-+}
-+
-+static int pm_lock_state(unsigned int s_bits, unsigned int flag,
-+                    unsigned int timeout)
-+{
-+      switch (s_bits) {
-+      case LCD_NORMAL:
-+      case LCD_DIM:
-+      case LCD_OFF:
-+              break;
-+      default:
-+              return -1;
-+      }
-+      if (flag & GOTO_STATE_NOW)
-+              /* if the flag is true, go to the locking state directly */
-+              s_bits = s_bits | (s_bits << SHIFT_CHANGE_STATE);
-+      if (flag & HOLD_KEY_BLOCK)
-+              s_bits = s_bits | (1 << SHIFT_HOLD_KEY_BLOCK);
-+
-+      return send_msg(s_bits, timeout, 0);
-+}
-+
-+static int pm_unlock_state(unsigned int s_bits, unsigned int flag)
-+{
-+      switch (s_bits) {
-+      case LCD_NORMAL:
-+      case LCD_DIM:
-+      case LCD_OFF:
-+              break;
-+      default:
-+              return -1;
-+      }
-+
-+      s_bits = (s_bits << SHIFT_UNLOCK);
-+      s_bits = (s_bits | (flag << SHIFT_UNLOCK_PARAMETER));
-+      return send_msg(s_bits, 0, 0);
-+}
-+
-+#endif
- static void timeout_cb(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
-     struct device_info *d = userdata;
-+#ifdef USE_PM_LOCK
-+    int ret = -1;
-+#endif
-+
-     pa_assert(d);
-     d->userdata->core->mainloop->time_restart(d->time_event, NULL);
-@@ -92,12 +221,33 @@ static void timeout_cb(pa_mainloop_api*a, pa_time_event* e, const struct timeval
-         pa_log_info("Sink %s idle for too long, suspending ...", d->sink->name);
-         pa_sink_suspend(d->sink, true, PA_SUSPEND_IDLE);
-         pa_core_maybe_vacuum(d->userdata->core);
-+#ifdef USE_PM_LOCK
-+              UPDATE_PM_UNLOCK(d->userdata->pm_state, PM_TYPE_SINK);
-+              if(!(d->userdata->pm_state)) {
-+                      ret = pm_unlock_state(LCD_OFF, PM_SLEEP_MARGIN);
-+                      if(ret != -1)
-+                              pa_log_info("sink pm_unlock_state success [%d]", ret);
-+                      else
-+                              pa_log_error("sink pm_unlock_state failed [%d]", ret);
-+              }
-+#endif /* USE_PM_LOCK */
-     }
-     if (d->source && pa_source_check_suspend(d->source) <= 0 && !(d->source->suspend_cause & PA_SUSPEND_IDLE)) {
-         pa_log_info("Source %s idle for too long, suspending ...", d->source->name);
-         pa_source_suspend(d->source, true, PA_SUSPEND_IDLE);
-         pa_core_maybe_vacuum(d->userdata->core);
-+#ifdef USE_PM_LOCK
-+
-+        UPDATE_PM_UNLOCK(d->userdata->pm_state, PM_TYPE_SOURCE);
-+        if(!(d->userdata->pm_state)) {
-+                      ret = pm_unlock_state(LCD_OFF, PM_SLEEP_MARGIN);
-+                      if(ret != -1)
-+                              pa_log_info("source pm_unlock_state success [%d]", ret);
-+                      else
-+                              pa_log_error("source pm_unlock_state failed [%d]", ret);
-+              }
-+#endif /* USE_PM_LOCK */
-     }
- }
-@@ -117,17 +267,39 @@ static void restart(struct device_info *d) {
- }
- static void resume(struct device_info *d) {
-+#ifdef USE_PM_LOCK
-+    int ret = -1;
-+#endif
-+
-     pa_assert(d);
-     d->userdata->core->mainloop->time_restart(d->time_event, NULL);
-     if (d->sink) {
--        pa_log_debug("Sink %s becomes busy, resuming.", d->sink->name);
-+#ifdef USE_PM_LOCK
-+              UPDATE_PM_LOCK(d->userdata->pm_state, PM_TYPE_SINK);
-+              ret = pm_lock_state(LCD_OFF, STAY_CUR_STATE, 0);
-+              if(ret != -1) {
-+                      pa_log_info("sink pm_lock_state success [%d]", ret);
-+              } else {
-+                      pa_log_error("sink pm_lock_state failed [%d]", ret);
-+              }
-+#endif /* USE_PM_LOCK */
-+        pa_log_debug("Sink %s becomes busy.", d->sink->name);
-         pa_sink_suspend(d->sink, false, PA_SUSPEND_IDLE);
-     }
-     if (d->source) {
--        pa_log_debug("Source %s becomes busy, resuming.", d->source->name);
-+#ifdef USE_PM_LOCK
-+              UPDATE_PM_LOCK(d->userdata->pm_state, PM_TYPE_SOURCE);
-+              ret = pm_lock_state(LCD_OFF, STAY_CUR_STATE, 0);
-+              if(ret != -1) {
-+                      pa_log_info("source pm_lock_state success [%d]", ret);
-+              } else {
-+                      pa_log_error("source pm_lock_state failed [%d]", ret);
-+              }
-+#endif /* USE_PM_LOCK */
-+        pa_log_debug("Source %s becomes busy.", d->source->name);
-         pa_source_suspend(d->source, false, PA_SUSPEND_IDLE);
-     }
- }
-@@ -462,6 +634,9 @@ int pa__init(pa_module*m) {
-     u->core = m->core;
-     u->timeout = timeout * PA_USEC_PER_SEC;
-     u->device_infos = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t) device_info_free);
-+#ifdef USE_PM_LOCK
-+    u->pm_state = 0x00;
-+#endif /* USE_PM_LOCK */
-     PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
-         device_new_hook_cb(m->core, PA_OBJECT(sink), u);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0035-Add-preload-fileter-for-resample-samsung.patch.gz b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0035-Add-preload-fileter-for-resample-samsung.patch.gz
deleted file mode 100644 (file)
index a8f29d7..0000000
Binary files a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0035-Add-preload-fileter-for-resample-samsung.patch.gz and /dev/null differ
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0036-Enhance-for-echo-cancel-samsung.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0036-Enhance-for-echo-cancel-samsung.patch
deleted file mode 100644 (file)
index 19bbb16..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-From: "vivian,zhang" <vivian.zhang@intel.com>
-Date: Tue, 18 Jun 2013 16:18:58 +0800
-Subject: Enhance for echo cancel - samsung
-
-Change-Id: Ibd59e7e033d5a6789ddc7d5ef39e23f26dcf55cc
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/Makefile.am                              |   2 +-
- src/map-file                                 |   2 +
- src/modules/echo-cancel/module-echo-cancel.c |  55 +++++++++++++++
- src/pulse/ext-echo-cancel.c                  | 100 +++++++++++++++++++++++++++
- src/pulse/ext-echo-cancel.h                  |  49 +++++++++++++
- 5 files changed, 207 insertions(+), 1 deletion(-)
- create mode 100644 src/pulse/ext-echo-cancel.c
- create mode 100644 src/pulse/ext-echo-cancel.h
-
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 12bb73e..ae841e3 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -1950,7 +1950,7 @@ module_echo_cancel_la_SOURCES = \
-               modules/echo-cancel/null.c \
-               modules/echo-cancel/echo-cancel.h
- module_echo_cancel_la_LDFLAGS = $(MODULE_LDFLAGS)
--module_echo_cancel_la_LIBADD = $(MODULE_LIBADD) $(LIBSPEEX_LIBS)
-+module_echo_cancel_la_LIBADD = libprotocol-native.la $(MODULE_LIBADD) $(LIBSPEEX_LIBS)
- module_echo_cancel_la_CFLAGS = $(AM_CFLAGS) $(SERVER_CFLAGS) $(LIBSPEEX_CFLAGS)
- if HAVE_ADRIAN_EC
- module_echo_cancel_la_SOURCES += \
-diff --git a/src/map-file b/src/map-file
-index 95364ae..d51596c 100644
---- a/src/map-file
-+++ b/src/map-file
-@@ -182,6 +182,8 @@ pa_ext_node_manager_connect_nodes;
- pa_ext_node_manager_disconnect_nodes;
- pa_ext_node_manager_subscribe;
- pa_ext_node_manager_set_subscribe_cb;
-+pa_ext_echo_cancel_set_volume;
-+pa_ext_echo_cancel_set_device;
- pa_format_info_copy;
- pa_format_info_free;
- pa_format_info_from_string;
-diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
-index fbdb3b3..29eed13 100644
---- a/src/modules/echo-cancel/module-echo-cancel.c
-+++ b/src/modules/echo-cancel/module-echo-cancel.c
-@@ -53,6 +53,9 @@
- #include <pulsecore/sample-util.h>
- #include <pulsecore/ltdl-helper.h>
-+#include <pulsecore/protocol-native.h>
-+#include <pulsecore/pstream-util.h>
-+
- #include "module-echo-cancel-symdef.h"
- PA_MODULE_AUTHOR("Wim Taymans");
-@@ -94,6 +97,11 @@ typedef enum {
- #endif
- } pa_echo_canceller_method_t;
-+enum {
-+      AEC_SET_VOLUME,
-+      AEC_SET_DEVICE,
-+};
-+
- #ifdef HAVE_WEBRTC
- #define DEFAULT_ECHO_CANCELLER "webrtc"
- #else
-@@ -255,6 +263,8 @@ struct userdata {
-     struct {
-         pa_cvolume current_volume;
-     } thread_info;
-+
-+    pa_native_protocol *protocol;
- };
- static void source_output_snapshot_within_thread(struct userdata *u, struct snapshot *snapshot);
-@@ -1602,6 +1612,43 @@ static pa_echo_canceller_method_t get_ec_method_from_string(const char *method)
-     return PA_ECHO_CANCELLER_INVALID;
- }
-+static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
-+      uint32_t command;
-+      uint32_t value;
-+      pa_tagstruct *reply = NULL;
-+      pa_assert(p);
-+      pa_assert(m);
-+      pa_assert(c);
-+      pa_assert(t);
-+
-+      if (pa_tagstruct_getu32(t, &command) < 0)
-+      goto fail;
-+
-+      reply = pa_tagstruct_new(NULL, 0);
-+      pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
-+      pa_tagstruct_putu32(reply, tag);
-+
-+      switch (command) {
-+              case AEC_SET_VOLUME: {
-+                      pa_tagstruct_getu32(t,&value);
-+                      pa_log_debug("AEC_SET_VOLUME in echo cancel = %d",value);
-+              break;
-+      }
-+              case AEC_SET_DEVICE: {
-+                      pa_tagstruct_getu32(t,&value);
-+                      pa_log_debug("AEC_SET_DEVICE in echo cancel = %d",value);
-+              break;
-+      }
-+      default:
-+              goto fail;
-+      }
-+      pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
-+      return 0;
-+
-+fail:
-+      return -1;
-+}
-+
- /* Common initialisation bits between module-echo-cancel and the standalone
-  * test program.
-  *
-@@ -1992,6 +2039,9 @@ int pa__init(pa_module*m) {
-     u->thread_info.current_volume = u->source->reference_volume;
-+    u->protocol = pa_native_protocol_get(m->core);
-+    pa_native_protocol_install_ext(u->protocol, m, extension_cb);
-+
-     pa_sink_put(u->sink);
-     pa_source_put(u->source);
-@@ -2069,6 +2119,11 @@ void pa__done(pa_module*m) {
-         pa_xfree(u->ec);
-     }
-+    if (u->protocol) {
-+        pa_native_protocol_remove_ext(u->protocol, m);
-+        pa_native_protocol_unref(u->protocol);
-+    }
-+
-     if (u->asyncmsgq)
-         pa_asyncmsgq_unref(u->asyncmsgq);
-diff --git a/src/pulse/ext-echo-cancel.c b/src/pulse/ext-echo-cancel.c
-new file mode 100644
-index 0000000..9339939
---- /dev/null
-+++ b/src/pulse/ext-echo-cancel.c
-@@ -0,0 +1,100 @@
-+/***
-+  This file is part of PulseAudio.
-+
-+  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 <pulse/context.h>
-+#include <pulse/gccmacro.h>
-+#include <pulse/xmalloc.h>
-+
-+#include <pulsecore/macro.h>
-+#include <pulsecore/pstream-util.h>
-+#include <pulsecore/log.h>
-+#include "internal.h"
-+#include "operation.h"
-+#include "fork-detect.h"
-+
-+#include "ext-echo-cancel.h"
-+
-+enum {
-+      AEC_SET_VOLUME,
-+      AEC_SET_DEVICE,
-+};
-+
-+pa_operation *pa_ext_echo_cancel_set_device (
-+                              pa_context *c,
-+                              int device,
-+                              pa_context_success_cb_t cb,
-+                              void *userdata) {
-+
-+      uint32_t tag;
-+      pa_operation *o = NULL;
-+      pa_tagstruct *t = NULL;
-+
-+      pa_assert(c);
-+      pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+      PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+      PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+      PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
-+
-+      o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+      t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
-+      pa_tagstruct_putu32(t, PA_INVALID_INDEX);
-+      pa_tagstruct_puts(t, "module-echo-cancel");
-+      pa_tagstruct_putu32(t, AEC_SET_DEVICE);
-+      pa_tagstruct_putu32(t, device);
-+
-+      pa_pstream_send_tagstruct(c->pstream, t);
-+      pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+      return o;
-+}
-+
-+
-+pa_operation *pa_ext_echo_cancel_set_volume (
-+                              pa_context *c,
-+                              int volume,
-+                              pa_context_success_cb_t cb,
-+                              void *userdata) {
-+
-+      uint32_t tag;
-+      pa_operation *o = NULL;
-+      pa_tagstruct *t = NULL;
-+
-+      pa_assert(c);
-+      pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+      PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+      PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+      PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
-+
-+      o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+      t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
-+      pa_tagstruct_putu32(t, PA_INVALID_INDEX);
-+      pa_tagstruct_puts(t, "module-echo-cancel");
-+      pa_tagstruct_putu32(t, AEC_SET_VOLUME);
-+      pa_tagstruct_putu32(t, volume);
-+
-+      pa_pstream_send_tagstruct(c->pstream, t);
-+      pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+      return o;
-+}
-diff --git a/src/pulse/ext-echo-cancel.h b/src/pulse/ext-echo-cancel.h
-new file mode 100644
-index 0000000..12e4eeb
---- /dev/null
-+++ b/src/pulse/ext-echo-cancel.h
-@@ -0,0 +1,49 @@
-+#ifndef foopulseechocancelfoo
-+#define foopulseechocancelfoo
-+
-+/***
-+  This file is part of PulseAudio.
-+
-+  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/context.h>
-+#include <pulse/version.h>
-+
-+/** \file
-+ *
-+ * Routines for controlling module-echo-cancel
-+ */
-+
-+PA_C_DECL_BEGIN
-+
-+/** Set volume to AEC module */
-+pa_operation *pa_ext_echo_cancel_set_volume (
-+        pa_context *c,
-+        int volume,
-+        pa_context_success_cb_t cb,
-+        void *userdata);
-+
-+pa_operation *pa_ext_echo_cancel_set_device (
-+        pa_context *c,
-+        int device,
-+        pa_context_success_cb_t cb,
-+        void *userdata);
-+
-+
-+PA_C_DECL_END
-+
-+#endif
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0037-add-support-for-dlog-samsung.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0037-add-support-for-dlog-samsung.patch
deleted file mode 100644 (file)
index 33c38c3..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-From: "vivian,zhang" <vivian.zhang@intel.com>
-Date: Tue, 18 Jun 2013 16:20:04 +0800
-Subject: add support for dlog - samsung
-
-Change-Id: Ieddf2f3bdab50926372e9e2b5cedb2756b6cfd5c
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- configure.ac                | 18 +++++++++
- src/Makefile.am             |  9 +++++
- src/daemon/cmdline.c        |  8 +++-
- src/daemon/daemon-conf.c    | 10 ++++-
- src/pulsecore/cli-command.c |  8 ++++
- src/pulsecore/log.c         | 95 +++++++++++++++++++++++++++++++++++++++++++++
- src/pulsecore/log.h         |  4 ++
- 7 files changed, 150 insertions(+), 2 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index 9a79b36..c0beac0 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -643,6 +643,24 @@ PKG_CHECK_MODULES(LIBJSON, [ json-c >= 0.11 ], [],
- PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.20 ])
-+dnl use dlog --------------------------------------------------------------------------
-+AC_ARG_ENABLE(dlog, AC_HELP_STRING([--enable-dlog], [using dlog]),
-+[
-+ case "${enableval}" in
-+       yes) USE_DLOG=yes ;;
-+       no)  USE_DLOG=no ;;
-+       *)   AC_MSG_ERROR(bad value ${enableval} for --enable-dlog) ;;
-+ esac
-+ ],[USE_DLOG=no])
-+
-+if test "x$USE_DLOG" = "xyes"; then
-+      PKG_CHECK_MODULES(DLOG, dlog)
-+      AC_SUBST(DLOG_CFLAGS)
-+      AC_SUBST(DLOG_LIBS)
-+fi
-+AM_CONDITIONAL(USE_DLOG, test "x$USE_DLOG" = "xyes")
-+dnl end --------------------------------------------------------------------
-+
- #### atomic-ops ####
- AC_MSG_CHECKING([whether we need libatomic_ops])
-diff --git a/src/Makefile.am b/src/Makefile.am
-index ae841e3..3e41300 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -172,6 +172,10 @@ else
- pulseaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(IMMEDIATE_LDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f))
- endif
-+if USE_DLOG
-+pulseaudio_CFLAGS += -DUSE_DLOG
-+endif
-+
- ###################################
- #       Utility programs          #
- ###################################
-@@ -740,6 +744,11 @@ libpulsecommon_@PA_MAJORMINOR@_la_CFLAGS += $(DBUS_CFLAGS)
- libpulsecommon_@PA_MAJORMINOR@_la_LIBADD += $(DBUS_LIBS)
- endif
-+if USE_DLOG
-+libpulsecommon_@PA_MAJORMINOR@_la_CFLAGS += $(DLOG_CFLAGS) -DUSE_DLOG
-+libpulsecommon_@PA_MAJORMINOR@_la_LIBADD += $(DLOG_LIBS)
-+endif
-+
- ###################################
- #         Client library          #
- ###################################
-diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c
-index 68579c5..5bb1a0a 100644
---- a/src/daemon/cmdline.c
-+++ b/src/daemon/cmdline.c
-@@ -140,8 +140,12 @@ void pa_cmdline_help(const char *argv0) {
-            "      --scache-idle-time=SECS           Unload autoloaded samples when idle and\n"
-            "                                        this time passed\n"
-            "      --log-level[=LEVEL]               Increase or set verbosity level\n"
--           "  -v  --verbose                         Increase the verbosity level\n"
-+           "  -v                                    Increase the verbosity level\n"
-+#ifdef USE_DLOG
-+           "      --log-target={auto,syslog,stderr,file:PATH,newfile:PATH,dlog,dlog-color}\n"
-+#else
-            "      --log-target={auto,syslog,stderr,file:PATH,newfile:PATH}\n"
-+#endif
-            "                                        Specify the log target\n"
-            "      --log-meta[=BOOL]                 Include code location in log messages\n"
-            "      --log-time[=BOOL]                 Include timestamps in log messages\n"
-@@ -325,6 +329,8 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d
-                 if (pa_daemon_conf_set_log_target(conf, optarg) < 0) {
- #ifdef HAVE_JOURNAL
-                     pa_log(_("Invalid log target: use either 'syslog', 'journal','stderr' or 'auto' or a valid file name 'file:<path>', 'newfile:<path>'."));
-+#elif defined(USE_DLOG)
-+                    pa_log(_("Invalid log target: use either 'syslog', 'stderr' or 'auto' or a valid file name 'file:<path>', 'newfile:<path>' or 'dlog' or 'dlog-color'."));
- #else
-                     pa_log(_("Invalid log target: use either 'syslog', 'stderr' or 'auto' or a valid file name 'file:<path>', 'newfile:<path>'."));
- #endif
-diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
-index ce777a6..1dde213 100644
---- a/src/daemon/daemon-conf.c
-+++ b/src/daemon/daemon-conf.c
-@@ -188,9 +188,17 @@ int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) {
-         if (!log_target)
-             return -1;
-+
-+        c->log_target = log_target;
-     }
--    c->log_target = log_target;
-+#ifdef USE_DLOG
-+    else if (!strcmp(string, "dlog")) {
-+        c->log_target = PA_LOG_DLOG;
-+    } else if (!strcmp(string, "dlog-color")) {
-+        c->log_target = PA_LOG_DLOG_COLOR;
-+    }
-+#endif
-     return 0;
- }
-diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
-index 8c956ac..2497b41 100644
---- a/src/pulsecore/cli-command.c
-+++ b/src/pulsecore/cli-command.c
-@@ -188,7 +188,11 @@ static const struct command commands[] = {
-     { "kill-client",             pa_cli_command_kill_client,        "Kill a client (args: index)", 2},
-     { "kill-sink-input",         pa_cli_command_kill_sink_input,    "Kill a sink input (args: index)", 2},
-     { "kill-source-output",      pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
-+#ifdef USE_DLOG
-+    { "set-log-target",          pa_cli_command_log_target,         "Change the log target (args: null|auto|syslog|stderr|file:PATH|newfile:PATH|dlog|dlog-color)", 2},
-+#else
-     { "set-log-target",          pa_cli_command_log_target,         "Change the log target (args: null|auto|syslog|stderr|file:PATH|newfile:PATH)", 2},
-+#endif
-     { "set-log-level",           pa_cli_command_log_level,          "Change the log level (args: numeric level)", 2},
-     { "set-log-meta",            pa_cli_command_log_meta,           "Show source code location in log messages (args: bool)", 2},
-     { "set-log-time",            pa_cli_command_log_time,           "Show timestamps in log messages (args: bool)", 2},
-@@ -1508,7 +1512,11 @@ static int pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf
-     pa_assert(fail);
-     if (!(m = pa_tokenizer_get(t, 1))) {
-+#ifdef USE_DLOG
-+        pa_strbuf_puts(buf, "You need to specify a log target (null|auto|syslog|stderr|file:PATH|newfile:PATH|dlog|dlog-color).\n");
-+#else
-         pa_strbuf_puts(buf, "You need to specify a log target (null|auto|syslog|stderr|file:PATH|newfile:PATH).\n");
-+#endif
-         return -1;
-     }
-diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c
-index cf96dce..dfb1d0f 100644
---- a/src/pulsecore/log.c
-+++ b/src/pulsecore/log.c
-@@ -61,6 +61,27 @@
- #include "log.h"
-+#ifdef USE_DLOG
-+#include <dlog.h>
-+#define       DLOG_TAG        "PULSEAUDIO"
-+
-+#define COLOR_BLACK           30
-+#define COLOR_RED             31
-+#define COLOR_GREEN           32
-+#define COLOR_BLUE            34
-+#define COLOR_MAGENTA         35
-+#define COLOR_CYAN            36
-+#define COLOR_WHITE           97
-+#define COLOR_B_GRAY          100
-+#define COLOR_B_RED           101
-+#define COLOR_B_GREEN         102
-+#define COLOR_B_YELLOW                103
-+#define COLOR_B_BLUE          104
-+#define COLOR_B_MAGENTA       105
-+#define COLOR_B_CYAN          106
-+#define COLOR_REVERSE         7
-+
-+#endif
- #define ENV_LOG_SYSLOG "PULSE_LOG_SYSLOG"
- #define ENV_LOG_LEVEL "PULSE_LOG"
- #define ENV_LOG_COLORS "PULSE_LOG_COLORS"
-@@ -545,6 +566,74 @@ void pa_log_levelv_meta(
-                 break;
-             }
-+
-+#ifdef USE_DLOG
-+            case PA_LOG_DLOG: {
-+                char *local_t;
-+
-+                openlog(ident, LOG_PID, LOG_USER);
-+
-+                if ((local_t = pa_utf8_to_locale(t)))
-+                    t = local_t;
-+
-+                switch (level)
-+                {
-+                                      case PA_LOG_DEBUG:
-+                                              SLOG (LOG_DEBUG, DLOG_TAG, "%s%s%s%s",  timestamp, location, t, pa_strempty(bt));
-+                                              break;
-+                                      case PA_LOG_INFO:
-+                                      case PA_LOG_NOTICE:     // no notice category in dlog, use info instead.
-+                                              SLOG (LOG_INFO, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
-+                                              break;
-+                                      case PA_LOG_WARN:
-+                                              SLOG (LOG_WARN, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
-+                                              break;
-+                                      case PA_LOG_ERROR:
-+                                              SLOG (LOG_ERROR, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
-+                                              break;
-+                                      default:
-+                                              SLOG (LOG_DEBUG, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
-+                                              break;
-+                }
-+
-+                pa_xfree(local_t);
-+
-+                break;
-+            }
-+            case PA_LOG_DLOG_COLOR: {
-+                              char *local_t;
-+
-+                              openlog(ident, LOG_PID, LOG_USER);
-+
-+                              if ((local_t = pa_utf8_to_locale(t)))
-+                                      t = local_t;
-+
-+                              switch (level)
-+                              {
-+                                      case PA_LOG_DEBUG:
-+                                              SLOG (LOG_DEBUG, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_GREEN, timestamp, location, t, pa_strempty(bt));
-+                                              break;
-+                                      case PA_LOG_INFO:
-+                                      case PA_LOG_NOTICE:     // no notice category in dlog, use info instead.
-+                                              SLOG (LOG_INFO, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_BLUE, timestamp, location, t, pa_strempty(bt));
-+                                              break;
-+                                      case PA_LOG_WARN:
-+                                              SLOG (LOG_WARN, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_MAGENTA, timestamp, location, t, pa_strempty(bt));
-+                                              break;
-+                                      case PA_LOG_ERROR:
-+                                              SLOG (LOG_ERROR, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_RED, timestamp, location, t, pa_strempty(bt));
-+                                              break;
-+                                      default:
-+                                              SLOG (LOG_DEBUG, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
-+                                              break;
-+                              }
-+
-+                              pa_xfree(local_t);
-+
-+                              break;
-+                      }
-+
-+#endif
-             case PA_LOG_NULL:
-             default:
-                 break;
-@@ -629,6 +718,12 @@ pa_log_target *pa_log_parse_target(const char *string) {
-         t = pa_log_target_new(PA_LOG_FILE, string + 5);
-     else if (pa_startswith(string, "newfile:"))
-         t = pa_log_target_new(PA_LOG_NEWFILE, string + 8);
-+#ifdef USE_DLOG
-+    else if (pa_streq(string, "dlog"))
-+        t = pa_log_target_new(PA_LOG_DLOG, NULL);
-+    else if (pa_streq(string, "dlog-color"))
-+        t = pa_log_target_new(PA_LOG_DLOG_COLOR, NULL);
-+#endif
-     else
-         pa_log(_("Invalid log target."));
-diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h
-index 5e9611d..031040f 100644
---- a/src/pulsecore/log.h
-+++ b/src/pulsecore/log.h
-@@ -41,6 +41,10 @@ typedef enum pa_log_target_type {
-     PA_LOG_NULL,        /* to /dev/null */
-     PA_LOG_FILE,        /* to a user specified file */
-     PA_LOG_NEWFILE,     /* with an automatic suffix to avoid overwriting anything */
-+#ifdef USE_DLOG
-+    PA_LOG_DLOG,
-+    PA_LOG_DLOG_COLOR,
-+#endif
- } pa_log_target_type_t;
- typedef enum pa_log_level {
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0038-add-policy-module-samsung.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0038-add-policy-module-samsung.patch
deleted file mode 100644 (file)
index fb976b1..0000000
+++ /dev/null
@@ -1,1317 +0,0 @@
-From: "vivian,zhang" <vivian.zhang@intel.com>
-Date: Tue, 18 Jun 2013 16:21:32 +0800
-Subject: add policy module - samsung
-
-Change-Id: I2111a9c4dc0a371dbea5b347cf77adbe8f930528
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- configure.ac                |  18 +
- src/Makefile.am             |  28 +-
- src/modules/module-policy.c | 926 ++++++++++++++++++++++++++++++++++++++++++++
- src/pulse/ext-policy.c      | 177 +++++++++
- src/pulse/ext-policy.h      |  61 +++
- src/pulse/proplist.h        |   3 +
- 6 files changed, 1211 insertions(+), 2 deletions(-)
- create mode 100644 src/modules/module-policy.c
- create mode 100644 src/pulse/ext-policy.c
- create mode 100644 src/pulse/ext-policy.h
-
-diff --git a/configure.ac b/configure.ac
-index c0beac0..0e205d3 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -643,6 +643,24 @@ PKG_CHECK_MODULES(LIBJSON, [ json-c >= 0.11 ], [],
- PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.20 ])
-+dnl use samsung policy module --------------------------------------------------------
-+AC_ARG_ENABLE(samsung-policy, AC_HELP_STRING([--enable-samsung-policy], [using samsung-policy]),
-+[
-+ case "${enableval}" in
-+       yes) USE_SAMSUNG_POLICY=yes ;;
-+       no)  USE_SAMSUNG_POLICY=no ;;
-+       *)   AC_MSG_ERROR(bad value ${enableval} for --enable-samsung_policy) ;;
-+ esac
-+ ],[USE_SAMSUNG_POLICY=no])
-+
-+if test "x$USE_SAMSUNG_POLICY" = "xyes"; then
-+      PKG_CHECK_MODULES(VCONF, vconf)
-+      AC_SUBST(VCONF_CFLAGS)
-+      AC_SUBST(VCONF_LIBS)
-+fi
-+AM_CONDITIONAL(USE_SAMSUNG_POLICY, test "x$USE_SAMSUNG_POLICY" = "xyes")
-+dnl end --------------------------------------------------------------------
-+
- dnl use dlog --------------------------------------------------------------------------
- AC_ARG_ENABLE(dlog, AC_HELP_STRING([--enable-dlog], [using dlog]),
- [
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 3e41300..4872dfd 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -149,7 +149,7 @@ pulseaudio_SOURCES = \
-               daemon/ltdl-bind-now.c daemon/ltdl-bind-now.h \
-               daemon/main.c
--pulseaudio_CFLAGS = $(AM_CFLAGS) $(CAP_CFLAGS)
-+pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS) $(CAP_CFLAGS) $(DBUS_CFLAGS)
- pulseaudio_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la $(LIBLTDL) $(CAP_LIBS)
- # This is needed because automake doesn't properly expand the foreach below
- pulseaudio_DEPENDENCIES = libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la $(PREOPEN_LIBS)
-@@ -787,6 +787,11 @@ pulseinclude_HEADERS = \
-               pulse/volume.h \
-               pulse/xmalloc.h
-+if USE_SAMSUNG_POLICY
-+pulseinclude_HEADERS += \
-+              pulse/ext-policy.h
-+endif
-+
- lib_LTLIBRARIES = \
-               libpulse.la \
-               libpulse-simple.la
-@@ -833,6 +838,11 @@ libpulse_la_SOURCES = \
-               pulse/volume.c pulse/volume.h \
-               pulse/xmalloc.c pulse/xmalloc.h
-+if USE_SAMSUNG_POLICY
-+libpulse_la_SOURCES += \
-+        pulse/ext-policy.c pulse/ext-policy.h
-+endif
-+
- libpulse_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(LIBJSON_CFLAGS)
- libpulse_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) $(LTLIBICONV) $(LIBJSON_LIBS) libpulsecommon-@PA_MAJORMINOR@.la
- libpulse_la_LDFLAGS = $(AM_LDFLAGS) $(VERSIONING_LDFLAGS) -version-info $(LIBPULSE_VERSION_INFO)
-@@ -1088,6 +1098,10 @@ if HAVE_DBUS
- # Serveral module (e.g. libalsa-util.la)
- modlibexec_LTLIBRARIES += \
-               module-console-kit.la
-+if USE_SAMSUNG_POLICY
-+modlibexec_LTLIBRARIES += \
-+              module-policy.la
-+endif
- endif
- modlibexec_LTLIBRARIES += \
-@@ -1470,7 +1484,10 @@ SYMDEF_FILES = \
-               module-switch-on-port-available-symdef.h \
-               module-filter-apply-symdef.h \
-               module-filter-heuristics-symdef.h
--
-+if USE_SAMSUNG_POLICY
-+SYMDEF_FILES += \
-+              module-policy-symdef.h
-+endif
- if HAVE_ESOUND
- SYMDEF_FILES += \
-               module-esound-protocol-tcp-symdef.h \
-@@ -2120,6 +2137,13 @@ module_rygel_media_server_la_LDFLAGS = $(MODULE_LDFLAGS)
- module_rygel_media_server_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) libprotocol-http.la
- module_rygel_media_server_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
-+if USE_SAMSUNG_POLICY
-+module_policy_la_SOURCES = modules/module-policy.c
-+module_policy_la_LDFLAGS = $(MODULE_LDFLAGS)
-+module_policy_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) $(VCONF_LIBS) libprotocol-native.la libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la
-+module_policy_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(VCONF_CFLAGS)
-+endif
-+
- ###################################
- #        Some minor stuff         #
- ###################################
-diff --git a/src/modules/module-policy.c b/src/modules/module-policy.c
-new file mode 100644
-index 0000000..2172018
---- /dev/null
-+++ b/src/modules/module-policy.c
-@@ -0,0 +1,926 @@
-+#ifdef HAVE_CONFIG_H
-+#include <config.h>
-+#endif
-+
-+#include <pulsecore/core.h>
-+#include <pulsecore/module.h>
-+#include <pulsecore/modargs.h>
-+#include <pulsecore/core-rtclock.h>
-+#include <pulsecore/core-util.h>
-+#include <pulsecore/log.h>
-+#include <stdbool.h>
-+#include <strings.h>
-+
-+#include <pulsecore/log.h>
-+#include <pulsecore/core-subscribe.h>
-+#include <pulsecore/sink-input.h>
-+#include <pulsecore/source-output.h>
-+#include <pulsecore/namereg.h>
-+#include <pulsecore/core-error.h>
-+
-+#include <pulsecore/protocol-native.h>
-+#include <pulsecore/pstream-util.h>
-+#include <vconf.h> // for mono
-+
-+#include "module-policy-symdef.h"
-+
-+PA_MODULE_AUTHOR("Seungbae Shin");
-+PA_MODULE_DESCRIPTION("Media Policy module");
-+PA_MODULE_VERSION(PACKAGE_VERSION);
-+PA_MODULE_LOAD_ONCE(true);
-+PA_MODULE_USAGE(
-+        "on_hotplug=<When new device becomes available, recheck streams?> ");
-+
-+static const char* const valid_modargs[] = {
-+    "on_hotplug",
-+    NULL
-+};
-+
-+struct userdata {
-+    pa_core *core;
-+    pa_module *module;
-+
-+    pa_hook_slot *sink_input_new_hook_slot,*sink_put_hook_slot;
-+
-+    pa_hook_slot *sink_input_unlink_slot,*sink_unlink_slot;
-+    pa_hook_slot *sink_input_unlink_post_slot, *sink_unlink_post_slot;
-+    pa_hook_slot *sink_input_move_start_slot,*sink_input_move_finish_slot;
-+    pa_subscription *subscription;
-+
-+    bool on_hotplug:1;
-+    int       bt_off_idx;
-+
-+    int is_mono;
-+    float balance;
-+    pa_module* module_mono_bt;
-+    pa_module* module_combined;
-+    pa_module* module_mono_combined;
-+    pa_native_protocol *protocol;
-+    pa_hook_slot *source_output_new_hook_slot;
-+};
-+
-+enum {
-+    SUBCOMMAND_TEST,
-+    SUBCOMMAND_MONO,
-+    SUBCOMMAND_BALANCE,
-+};
-+
-+/* DEFINEs */
-+#define AEC_SINK                      "alsa_output.0.analog-stereo.echo-cancel"
-+#define AEC_SOURCE                    "alsa_input.0.analog-stereo.echo-cancel"
-+#define       SINK_ALSA                       "alsa_output.0.analog-stereo"
-+#define SINK_MONO_ALSA                "mono_alsa"
-+#define SINK_MONO_BT          "mono_bt"
-+#define SINK_COMBINED         "combined"
-+#define SINK_MONO_COMBINED    "mono_combined"
-+#define POLICY_AUTO                   "auto"
-+#define POLICY_PHONE          "phone"
-+#define POLICY_ALL                    "all"
-+#define POLICY_VOIP                   "voip"
-+#define BLUEZ_API                     "bluez"
-+#define ALSA_API                      "alsa"
-+#define MONO_KEY                      VCONFKEY_SETAPPL_ACCESSIBILITY_MONO_AUDIO
-+
-+/* check if this sink is bluez */
-+static bool policy_is_bluez (pa_sink* sink)
-+{
-+      const char* api_name = NULL;
-+
-+      if (sink == NULL) {
-+              pa_log_warn ("input param sink is null");
-+              return false;
-+      }
-+
-+    api_name = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_API);
-+      if (api_name) {
-+              if (pa_streq (api_name, BLUEZ_API)) {
-+#ifdef DEBUG_DETAIL
-+                      pa_log_debug("[POLICY][%s] [%s] exists and it is [%s]...true !!", __func__, PA_PROP_DEVICE_API, api_name);
-+#endif
-+                      return true;
-+              } else {
-+#ifdef DEBUG_DETAIL
-+                      pa_log_debug("[POLICY][%s] [%s] exists, but not bluez...false !!", __func__, PA_PROP_DEVICE_API);
-+#endif
-+              }
-+      } else {
-+#ifdef DEBUG_DETAIL
-+              pa_log_debug("[POLICY][%s] No [%s] exists...false!!", __func__, PA_PROP_DEVICE_API);
-+#endif
-+      }
-+
-+      return false;
-+}
-+
-+/* check if this sink is bluez */
-+static bool policy_is_usb_alsa (pa_sink* sink)
-+{
-+      const char* api_name = NULL;
-+      const char* device_bus_name = NULL;
-+
-+      if (sink == NULL) {
-+              pa_log_warn ("input param sink is null");
-+              return false;
-+      }
-+
-+    api_name = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_API);
-+      if (api_name) {
-+              if (pa_streq (api_name, ALSA_API)) {
-+#ifdef DEBUG_DETAIL
-+                      pa_log_debug("[POLICY][%s] [%s] exists and it is [%s]...true !!", __func__, PA_PROP_DEVICE_API, api_name);
-+#endif
-+                      device_bus_name = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_BUS);
-+                      if (device_bus_name) {
-+                              if (pa_streq (device_bus_name, "usb")) {
-+                                      return true;
-+                              }
-+                      }
-+              } else {
-+#ifdef DEBUG_DETAIL
-+                      pa_log_debug("[POLICY][%s] [%s] exists, but not alsa...false !!", __func__, PA_PROP_DEVICE_API);
-+#endif
-+              }
-+      } else {
-+#ifdef DEBUG_DETAIL
-+              pa_log_debug("[POLICY][%s] No [%s] exists...false!!", __func__, PA_PROP_DEVICE_API);
-+#endif
-+      }
-+
-+      return false;
-+}
-+
-+/* Get sink by name */
-+static pa_sink* policy_get_sink_by_name (pa_core *c, const char* sink_name)
-+{
-+    pa_sink *s = NULL;
-+    uint32_t idx;
-+
-+    if (c == NULL || sink_name == NULL) {
-+              pa_log_warn ("input param is null");
-+              return NULL;
-+    }
-+
-+      PA_IDXSET_FOREACH(s, c->sinks, idx) {
-+              if (pa_streq (s->name, sink_name)) {
-+                      pa_log_debug ("[POLICY][%s] return [%p] for [%s]\n",  __func__, s, sink_name);
-+                      return s;
-+              }
-+      }
-+      return NULL;
-+}
-+
-+/* Get bt sink if available */
-+static pa_sink* policy_get_bt_sink (pa_core *c)
-+{
-+    pa_sink *s = NULL;
-+    uint32_t idx;
-+
-+    if (c == NULL) {
-+              pa_log_warn ("input param is null");
-+              return NULL;
-+    }
-+
-+      PA_IDXSET_FOREACH(s, c->sinks, idx) {
-+              if (policy_is_bluez (s)) {
-+                      pa_log_debug ("[POLICY][%s] return [%p] for [%s]\n", __func__, s, s->name);
-+                      return s;
-+              }
-+      }
-+      return NULL;
-+}
-+
-+/* Select sink for given condition */
-+static pa_sink* policy_select_proper_sink (pa_core *c, const char* policy, int is_mono)
-+{
-+      pa_sink* sink = NULL;
-+      pa_sink* bt_sink = NULL;
-+      pa_sink* def = NULL;
-+
-+      if (c == NULL || policy == NULL) {
-+              pa_log_warn ("input param is null");
-+              return NULL;
-+      }
-+
-+      pa_assert (c);
-+
-+      bt_sink = policy_get_bt_sink(c);
-+      def = pa_namereg_get_default_sink(c);
-+      if (def == NULL) {
-+              pa_log_warn ("POLICY][%s] pa_namereg_get_default_sink() returns null", __func__);
-+              return NULL;
-+      }
-+
-+      pa_log_debug ("[POLICY][%s] policy[%s], is_mono[%d], current default[%s], bt sink[%s]\n",
-+                      __func__, policy, is_mono, def->name, (bt_sink)? bt_sink->name:"null");
-+
-+      /* Select sink to */
-+      if (pa_streq(policy, POLICY_ALL)) {
-+              /* all */
-+              if (bt_sink) {
-+                      sink = policy_get_sink_by_name(c, (is_mono)? SINK_MONO_COMBINED : SINK_COMBINED);
-+              } else {
-+                      sink = policy_get_sink_by_name (c, (is_mono)? SINK_MONO_ALSA : SINK_ALSA);
-+              }
-+
-+      } else if (pa_streq(policy, POLICY_PHONE)) {
-+              /* phone */
-+              sink = policy_get_sink_by_name (c, (is_mono)? SINK_MONO_ALSA : SINK_ALSA);
-+      } else if (pa_streq(policy, POLICY_VOIP)) {
-+              /* VOIP */
-+              sink = policy_get_sink_by_name (c,AEC_SINK);
-+      } else {
-+              /* auto */
-+              if (policy_is_bluez(def)) {
-+                      sink = (is_mono)? policy_get_sink_by_name (c, SINK_MONO_BT) : def;
-+              } else if (policy_is_usb_alsa(def)) {
-+                      sink = def;
-+              } else {
-+                      sink = (is_mono)? policy_get_sink_by_name (c, SINK_MONO_ALSA) : def;
-+              }
-+      }
-+
-+      pa_log_debug ("[POLICY][%s] selected sink : [%s]\n", __func__, (sink)? sink->name : "null");
-+      return sink;
-+}
-+
-+static bool policy_is_filter (pa_sink_input* si)
-+{
-+      const char* role = NULL;
-+
-+      if (si == NULL) {
-+              pa_log_warn ("input param sink-input is null");
-+              return false;
-+      }
-+
-+      if ((role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE))) {
-+#ifdef DEBUG_DETAIL
-+              pa_log_debug("[POLICY][%s] Role of sink input [%d] = %s", __func__, si->index, role);
-+#endif
-+              if (pa_streq(role, "filter")) {
-+#ifdef DEBUG_DETAIL
-+                      pa_log_debug("[POLICY] no need to change of sink for %s", role);
-+#endif
-+                      return true;
-+              }
-+      }
-+
-+      return false;
-+}
-+
-+
-+
-+#define EXT_VERSION 1
-+
-+static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
-+  struct userdata *u = NULL;
-+  uint32_t command;
-+  pa_tagstruct *reply = NULL;
-+
-+  pa_sink_input *si = NULL;
-+  pa_sink *s = NULL;
-+  uint32_t idx;
-+  pa_sink* sink_to_move  = NULL;
-+
-+  pa_assert(p);
-+  pa_assert(m);
-+  pa_assert(c);
-+  pa_assert(t);
-+
-+  u = m->userdata;
-+
-+  if (pa_tagstruct_getu32(t, &command) < 0)
-+    goto fail;
-+
-+  reply = pa_tagstruct_new(NULL, 0);
-+  pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
-+  pa_tagstruct_putu32(reply, tag);
-+
-+  switch (command) {
-+    case SUBCOMMAND_TEST: {
-+              if (!pa_tagstruct_eof(t))
-+                      goto fail;
-+
-+              pa_tagstruct_putu32(reply, EXT_VERSION);
-+              break;
-+    }
-+
-+    case SUBCOMMAND_MONO: {
-+
-+        bool enable;
-+
-+        if (pa_tagstruct_get_boolean(t, &enable) < 0)
-+            goto fail;
-+
-+        pa_log_debug ("[POLICY][%s] new mono value = %d\n", __func__, enable);
-+        if (enable == u->is_mono) {
-+                      pa_log_debug ("[POLICY][%s] No changes in mono value = %d", __func__, u->is_mono);
-+                      break;
-+        }
-+
-+        u->is_mono = enable;
-+
-+              /* Move current sink-input to proper mono sink */
-+              PA_IDXSET_FOREACH(si, u->core->sink_inputs, idx) {
-+                      const char *policy = NULL;
-+
-+                      /* Skip this if it is already in the process of being moved
-+                       * anyway */
-+                      if (!si->sink)
-+                              continue;
-+
-+                      /* It might happen that a stream and a sink are set up at the
-+                         same time, in which case we want to make sure we don't
-+                         interfere with that */
-+                      if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si)))
-+                              continue;
-+
-+                      /* Get role (if role is filter, skip it) */
-+                      if (policy_is_filter(si))
-+                              continue;
-+
-+                      /* Check policy, if no policy exists, treat as AUTO */
-+                      if (!(policy = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_POLICY))) {
-+                              pa_log_debug("[POLICY] set policy of sink-input[%d] from [%s] to [auto]", si->index, "null");
-+                              policy  = POLICY_AUTO;
-+                      }
-+                      pa_log_debug("[POLICY] Policy of sink input [%d] = %s", si->index, policy);
-+
-+                      /* Select sink to move and move to it */
-+                      sink_to_move = policy_select_proper_sink (u->core, policy, u->is_mono);
-+                      if (sink_to_move) {
-+                              pa_log_debug("[POLICY][%s] Moving sink-input[%d] from [%s] to [%s]", __func__, si->index, si->sink->name, sink_to_move->name);
-+                              pa_sink_input_move_to(si, sink_to_move, false);
-+                      } else {
-+                              pa_log_debug("[POLICY][%s] Can't move sink-input....", __func__);
-+                      }
-+              }
-+        break;
-+    }
-+
-+    case SUBCOMMAND_BALANCE: {
-+              float balance;
-+              pa_cvolume cvol;
-+              pa_channel_map map;
-+
-+              if (pa_tagstruct_get_cvolume(t, &cvol) < 0)
-+                      goto fail;
-+
-+              pa_channel_map_init_stereo(&map);
-+              balance = pa_cvolume_get_balance(&cvol, &map);
-+
-+              pa_log_debug ("[POLICY][%s] new balance value = [%f]\n", __func__, balance);
-+
-+              if (balance == u->balance) {
-+                      pa_log_debug ("[POLICY][%s] No changes in balance value = [%f]", __func__, u->balance);
-+                      break;
-+              }
-+
-+              u->balance = balance;
-+
-+              /* Apply balance value to each Sinks */
-+              PA_IDXSET_FOREACH(s, u->core->sinks, idx) {
-+                      pa_cvolume* cvol = pa_sink_get_volume (s, false);
-+                      pa_cvolume_set_balance (cvol, &s->channel_map, u->balance);
-+                      pa_sink_set_volume(s, cvol, true, true);
-+              }
-+              break;
-+      }
-+
-+    default:
-+      goto fail;
-+  }
-+
-+  pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
-+  return 0;
-+
-+  fail:
-+
-+  if (reply)
-+        pa_tagstruct_free(reply);
-+
-+  return -1;
-+}
-+
-+/*  Called when new sink-input is creating  */
-+static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u)
-+{
-+    const char *policy = NULL;
-+
-+    pa_assert(c);
-+    pa_assert(new_data);
-+    pa_assert(u);
-+
-+    if (!new_data->proplist) {
-+        pa_log_debug("[POLICY] New stream lacks property data.");
-+        return PA_HOOK_OK;
-+    }
-+
-+    /* If sink-input has already sink, skip */
-+    if (new_data->sink) {
-+      /* sink-input with filter role will be also here because sink is already set */
-+#ifdef DEBUG_DETAIL
-+        pa_log_debug("[POLICY] Not setting device for stream [%s], because already set.",
-+                      pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME)));
-+#endif
-+        return PA_HOOK_OK;
-+    }
-+
-+    /* If no policy exists, skip */
-+    if (!(policy = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_POLICY))) {
-+        pa_log_debug("[POLICY][%s] Not setting device for stream [%s], because it lacks policy.",
-+                      __func__, pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME)));
-+        return PA_HOOK_OK;
-+    }
-+    pa_log_debug("[POLICY][%s] Policy for stream [%s] = [%s]",
-+              __func__, pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME)), policy);
-+
-+    /* Set proper sink to sink-input */
-+    pa_sink* new_sink = policy_select_proper_sink(c, policy, u->is_mono);
-+    if(new_sink != new_data->sink)
-+    {
-+        pa_sink_input_new_data_set_sink(new_data, new_sink, false);
-+    }
-+      /*new_data->save_sink = false;
-+      new_data->sink = policy_select_proper_sink (c, policy, u->is_mono);*/
-+      pa_log_debug("[POLICY][%s] set sink of sink-input to [%s]", __func__, (new_data->sink)? new_data->sink->name : "null");
-+
-+    return PA_HOOK_OK;
-+}
-+
-+/*  Called when new sink is added while sink-input is existing  */
-+static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u)
-+{
-+    pa_sink_input *si;
-+    pa_sink *sink_to_move;
-+    uint32_t idx;
-+    char *args = NULL;
-+
-+    bool is_bt;
-+    bool is_usb_alsa;
-+
-+    pa_assert(c);
-+    pa_assert(sink);
-+    pa_assert(u);
-+    pa_assert(u->on_hotplug);
-+
-+    /* If connected sink is BLUETOOTH, set as default */
-+    /* we are checking with device.api property */
-+    is_bt = policy_is_bluez(sink);
-+    is_usb_alsa = policy_is_usb_alsa(sink);
-+
-+      if (is_bt || is_usb_alsa) {
-+              pa_log_debug("[POLICY][%s] set default sink to sink[%s][%d]", __func__, sink->name, sink->index);
-+              pa_namereg_set_default_sink (c,sink);
-+      } else {
-+              pa_log_debug("[POLICY][%s] this sink [%s][%d] is not a bluez....return", __func__, sink->name, sink->index);
-+              return PA_HOOK_OK;
-+      }
-+
-+      if (is_bt) {
-+              /* Load mono_bt sink */
-+              args = pa_sprintf_malloc("sink_name=%s master=%s channels=1", SINK_MONO_BT, sink->name);
-+              u->module_mono_bt = pa_module_load(u->module->core, "module-remap-sink", args);
-+              pa_xfree(args);
-+
-+              /* load combine sink */
-+              args = pa_sprintf_malloc("sink_name=%s slaves=\"%s,%s\"", SINK_COMBINED, sink->name, SINK_ALSA);
-+              u->module_combined = pa_module_load(u->module->core, "module-combine", args);
-+              pa_xfree(args);
-+
-+              /* load mono_combine sink */
-+              args = pa_sprintf_malloc("sink_name=%s master=%s channels=1", SINK_MONO_COMBINED, SINK_COMBINED);
-+              u->module_mono_combined = pa_module_load(u->module->core, "module-remap-sink", args);
-+              pa_xfree(args);
-+      }
-+
-+      /* Iterate each sink inputs to decide whether we should move to new sink */
-+    PA_IDXSET_FOREACH(si, c->sink_inputs, idx) {
-+        const char *policy = NULL;
-+
-+        if (si->sink == sink)
-+              continue;
-+
-+        /* Skip this if it is already in the process of being moved
-+         * anyway */
-+        if (!si->sink)
-+            continue;
-+
-+        /* It might happen that a stream and a sink are set up at the
-+           same time, in which case we want to make sure we don't
-+           interfere with that */
-+        if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si)))
-+            continue;
-+
-+              /* Get role (if role is filter, skip it) */
-+        if (policy_is_filter(si))
-+              continue;
-+
-+              /* Check policy */
-+              if (!(policy = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_POLICY))) {
-+                      /* No policy exists, this means auto */
-+                      pa_log_debug("[POLICY][%s] set policy of sink-input[%d] from [%s] to [auto]", __func__, si->index, "null");
-+                      policy = POLICY_AUTO;
-+              }
-+
-+              sink_to_move = policy_select_proper_sink (c, policy, u->is_mono);
-+              if (sink_to_move) {
-+                      pa_log_debug("[POLICY][%s] Moving sink-input[%d] from [%s] to [%s]", __func__, si->index, si->sink->name, sink_to_move->name);
-+                      pa_sink_input_move_to(si, sink_to_move, false);
-+              } else {
-+                      pa_log_debug("[POLICY][%s] Can't move sink-input....",__func__);
-+              }
-+    }
-+
-+      /* Reset sink volume with balance from userdata */
-+      pa_cvolume* cvol = pa_sink_get_volume(sink, false);
-+      pa_cvolume_set_balance(cvol, &sink->channel_map, u->balance);
-+      pa_sink_set_volume(sink, cvol, true, true);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static void subscribe_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata)
-+{
-+    struct userdata *u = userdata;
-+    pa_sink *def;
-+    pa_sink_input *si;
-+    uint32_t idx2;
-+    pa_sink *sink_to_move = NULL;
-+    pa_assert(u);
-+
-+    pa_log_debug("[POLICY][%s] subscribe_cb() t=[0x%x], idx=[%d]", __func__, t, idx);
-+
-+    /* We only handle server changes */
-+    if (t == (PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE)) {
-+
-+      def = pa_namereg_get_default_sink(c);
-+              if (def == NULL) {
-+                      pa_log_warn("[POLICY][%s] pa_namereg_get_default_sink() returns null", __func__);
-+                      return;
-+              }
-+      pa_log_debug("[POLICY][%s] trying to move stream to current default sink = [%s]", __func__, def->name);
-+
-+      /* Iterate each sink inputs to decide whether we should move to new DEFAULT sink */
-+      PA_IDXSET_FOREACH(si, c->sink_inputs, idx2) {
-+                      const char *policy = NULL;
-+
-+                      if (!si->sink)
-+                              continue;
-+
-+                      /* Get role (if role is filter, skip it) */
-+                      if (policy_is_filter(si))
-+                              continue;
-+
-+                      /* Get policy */
-+                      if (!(policy = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_POLICY))) {
-+                              /* No policy exists, this means auto */
-+                              pa_log_debug("[POLICY][%s] set policy of sink-input[%d] from [%s] to [auto]", __func__, si->index, "null");
-+                              policy = POLICY_AUTO;
-+                      }
-+
-+                      sink_to_move = policy_select_proper_sink (c, policy, u->is_mono);
-+                      if (sink_to_move) {
-+                              /* Move sink-input to new DEFAULT sink */
-+                              pa_log_debug("[POLICY][%s] Moving sink-input[%d] from [%s] to [%s]", __func__, si->index, si->sink->name, sink_to_move->name);
-+                              pa_sink_input_move_to(si, sink_to_move, false);
-+                      }
-+      }
-+    }
-+}
-+
-+static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) {
-+    struct userdata *u = userdata;
-+    uint32_t idx;
-+    pa_sink *sink_to_move;
-+    pa_sink_input     *si;
-+
-+    pa_assert(c);
-+    pa_assert(sink);
-+    pa_assert(u);
-+
-+     /* There's no point in doing anything if the core is shut down anyway */
-+    if (c->state == PA_CORE_SHUTDOWN)
-+        return PA_HOOK_OK;
-+
-+    /* if unloading sink is not bt, just return */
-+      if (!policy_is_bluez (sink)) {
-+              pa_log_debug("[POLICY][%s] sink[%s][%d] unlinked but not a bluez....return\n", __func__,  sink->name, sink->index);
-+              return PA_HOOK_OK;
-+      }
-+
-+      pa_log_debug ("[POLICY][%s] SINK unlinked ================================ sink [%s][%d], bt_off_idx was [%d]",
-+                      __func__, sink->name, sink->index,u->bt_off_idx);
-+
-+      u->bt_off_idx = sink->index;
-+      pa_log_debug ("[POLICY][%s] bt_off_idx is set to [%d]", __func__, u->bt_off_idx);
-+
-+      /* BT sink is unloading, move sink-input to proper sink */
-+      PA_IDXSET_FOREACH(si, c->sink_inputs, idx) {
-+
-+              if (!si->sink)
-+                      continue;
-+
-+              /* Get role (if role is filter, skip it) */
-+              if (policy_is_filter(si))
-+                      continue;
-+
-+              /* Find who were using bt sink or bt related sink and move them to proper sink (alsa/mono_alsa) */
-+              if (pa_streq (si->sink->name, SINK_MONO_BT) ||
-+                      pa_streq (si->sink->name, SINK_MONO_COMBINED) ||
-+                      pa_streq (si->sink->name, SINK_COMBINED) ||
-+                      policy_is_bluez (si->sink)) {
-+
-+                      /* Move sink-input to proper sink : only alsa related sink is available now */
-+                      sink_to_move = policy_get_sink_by_name (c, (u->is_mono)? SINK_MONO_ALSA : SINK_ALSA);
-+                      if (sink_to_move) {
-+                              pa_log_debug("[POLICY][%s] Moving sink-input[%d] from [%s] to [%s]", __func__, si->index, si->sink->name, sink_to_move->name);
-+                              pa_sink_input_move_to(si, sink_to_move, false);
-+                      } else {
-+                              pa_log_warn("[POLICY][%s] No sink to move", __func__);
-+                      }
-+              }
-+      }
-+
-+      pa_log_debug ("[POLICY][%s] unload sink in dependencies", __func__);
-+
-+    /* Unload mono_combine sink */
-+    if (u->module_mono_combined) {
-+        pa_module_unload(u->module->core, u->module_mono_combined, true);
-+      u->module_mono_combined = NULL;
-+    }
-+
-+      /* Unload combine sink */
-+    if (u->module_combined) {
-+        pa_module_unload(u->module->core, u->module_combined, true);
-+        u->module_combined = NULL;
-+    }
-+
-+    /* Unload mono_bt sink */
-+      if (u->module_mono_bt) {
-+              pa_module_unload(u->module->core, u->module_mono_bt, true);
-+              u->module_mono_bt = NULL;
-+      }
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t sink_unlink_post_hook_callback(pa_core *c, pa_sink *sink, void* userdata) {
-+    struct userdata *u = userdata;
-+
-+    pa_assert(c);
-+    pa_assert(sink);
-+    pa_assert(u);
-+
-+    pa_log_debug("[POLICY][%s] SINK unlinked POST ================================ sink [%s][%d]", __func__, sink->name, sink->index);
-+
-+     /* There's no point in doing anything if the core is shut down anyway */
-+    if (c->state == PA_CORE_SHUTDOWN)
-+        return PA_HOOK_OK;
-+
-+    /* if unloading sink is not bt, just return */
-+      if (!policy_is_bluez (sink)) {
-+              pa_log_debug("[POLICY][%s] not a bluez....return\n", __func__);
-+              return PA_HOOK_OK;
-+      }
-+
-+    u->bt_off_idx = -1;
-+    pa_log_debug ("[POLICY][%s] bt_off_idx is cleared to [%d]", __func__, u->bt_off_idx);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t sink_input_move_start_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
-+    pa_core_assert_ref(core);
-+    pa_sink_input_assert_ref(i);
-+
-+    /* There's no point in doing anything if the core is shut down anyway */
-+   if (core->state == PA_CORE_SHUTDOWN)
-+       return PA_HOOK_OK;
-+
-+    pa_log_debug ("[POLICY][%s]  sink_input_move_start_cb -------------------------------------- sink-input [%d] was sink [%s][%d] : Trying to mute!!!",
-+              __func__, i->index, i->sink->name, i->sink->index);
-+    pa_sink_input_set_mute(i, true, false);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
-+    pa_core_assert_ref(core);
-+    pa_sink_input_assert_ref(i);
-+
-+    /* There's no point in doing anything if the core is shut down anyway */
-+   if (core->state == PA_CORE_SHUTDOWN)
-+       return PA_HOOK_OK;
-+
-+    pa_log_debug("[POLICY][%s] sink_input_move_finish_cb -------------------------------------- sink-input [%d], sink [%s][%d], bt_off_idx [%d] : %s",
-+              __func__, i->index, i->sink->name, i->sink->index, u->bt_off_idx,
-+              (u->bt_off_idx == -1)? "Trying to un-mute!!!!" : "skip un-mute...");
-+
-+    /* If sink input move is caused by bt sink unlink, then skip un-mute operation */
-+    if (u->bt_off_idx == -1) {
-+        pa_sink_input_set_mute(i, false, false);
-+    }
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_source* policy_get_source_by_name (pa_core *c, const char* source_name)
-+{
-+      pa_source *s = NULL;
-+      uint32_t idx;
-+
-+      if (c == NULL || source_name == NULL) {
-+              pa_log_warn ("input param is null");
-+              return NULL;
-+      }
-+
-+      PA_IDXSET_FOREACH(s, c->sources, idx) {
-+              if (pa_streq (s->name, source_name)) {
-+                      pa_log_debug ("[POLICY][%s] return [%p] for [%s]\n",  __func__, s, source_name);
-+                      return s;
-+              }
-+      }
-+      return NULL;
-+}
-+
-+/* Select source for given condition */
-+static pa_source* policy_select_proper_source (pa_core *c, const char* policy)
-+{
-+      pa_source* source = NULL;
-+      pa_source* def = NULL;
-+
-+      if (c == NULL || policy == NULL) {
-+              pa_log_warn ("input param is null");
-+              return NULL;
-+      }
-+
-+      pa_assert (c);
-+      def = pa_namereg_get_default_source(c);
-+      if (def == NULL) {
-+              pa_log_warn ("POLICY][%s] pa_namereg_get_default_source() returns null", __func__);
-+              return NULL;
-+      }
-+
-+      /* Select source  to */
-+      if (pa_streq(policy, POLICY_VOIP)) {
-+              source = policy_get_source_by_name (c, AEC_SOURCE);
-+
-+      } else {
-+              source = def;
-+      }
-+
-+      pa_log_debug ("[POLICY][%s] selected source : [%s]\n", __func__, (source)? source->name : "null");
-+      return source;
-+}
-+
-+
-+/*  Called when new source-output is creating  */
-+static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
-+      const char *policy = NULL;
-+      pa_assert(c);
-+      pa_assert(new_data);
-+      pa_assert(u);
-+
-+      if (!new_data->proplist) {
-+              pa_log_debug("New stream lacks property data.");
-+              return PA_HOOK_OK;
-+      }
-+
-+      if (new_data->source) {
-+              pa_log_debug("Not setting device for stream %s, because already set.", pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME)));
-+              return PA_HOOK_OK;
-+      }
-+
-+      /* If no policy exists, skip */
-+      if (!(policy = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_POLICY))) {
-+              pa_log_debug("[POLICY][%s] Not setting device for stream [%s], because it lacks policy.",
-+                              __func__, pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME)));
-+              return PA_HOOK_OK;
-+      }
-+      pa_log_debug("[POLICY][%s] Policy for stream [%s] = [%s]",
-+                      __func__, pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME)), policy);
-+
-+      /* Set proper source to source-output */
-+    pa_source* new_source = policy_select_proper_source(c, policy);
-+    if(new_source != new_data->source)
-+    {
-+        pa_source_output_new_data_set_source(new_data, new_source, false);
-+    }
-+      /*new_data->save_source= false;
-+      new_data->source= policy_select_proper_source (c, policy);*/
-+      pa_log_debug("[POLICY][%s] set source of source-input to [%s]", __func__, (new_data->source)? new_data->source->name : "null");
-+
-+      return PA_HOOK_OK;
-+}
-+
-+int pa__init(pa_module *m)
-+{
-+      pa_modargs *ma = NULL;
-+      struct userdata *u;
-+      bool on_hotplug = true, on_rescue = true;
-+
-+      pa_assert(m);
-+
-+      if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-+              pa_log("Failed to parse module arguments");
-+              goto fail;
-+      }
-+
-+      if (pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
-+              pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
-+              pa_log("on_hotplug= and on_rescue= expect boolean arguments");
-+              goto fail;
-+      }
-+
-+      m->userdata = u = pa_xnew0(struct userdata, 1);
-+      u->core = m->core;
-+      u->module = m;
-+      u->on_hotplug = on_hotplug;
-+
-+
-+      /* A little bit later than module-stream-restore */
-+      u->sink_input_new_hook_slot =
-+                      pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY+10, (pa_hook_cb_t) sink_input_new_hook_callback, u);
-+
-+      u->source_output_new_hook_slot =
-+                      pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY+10, (pa_hook_cb_t) source_output_new_hook_callback, u);
-+
-+      if (on_hotplug) {
-+              /* A little bit later than module-stream-restore */
-+              u->sink_put_hook_slot =
-+                      pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) sink_put_hook_callback, u);
-+      }
-+
-+      /* sink unlink comes before sink-input unlink */
-+      u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) sink_unlink_hook_callback, u);
-+      u->sink_unlink_post_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], PA_HOOK_EARLY, (pa_hook_cb_t) sink_unlink_post_hook_callback, u);
-+
-+      u->sink_input_move_start_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_move_start_cb, u);
-+      u->sink_input_move_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_move_finish_cb, u);
-+
-+      u->subscription = pa_subscription_new(u->core, PA_SUBSCRIPTION_MASK_SERVER, subscribe_cb, u);
-+
-+
-+      u->bt_off_idx = -1;     /* initial bt off sink index */
-+
-+      u->module_mono_bt = NULL;
-+      u->module_combined = NULL;
-+      u->module_mono_combined = NULL;
-+
-+    u->protocol = pa_native_protocol_get(m->core);
-+    pa_native_protocol_install_ext(u->protocol, m, extension_cb);
-+
-+    /* Get mono key value for init */
-+      vconf_get_bool(MONO_KEY, &u->is_mono);
-+
-+      pa_log_info("policy module is loaded\n");
-+
-+      if (ma)
-+              pa_modargs_free(ma);
-+
-+      return 0;
-+
-+fail:
-+      if (ma)
-+              pa_modargs_free(ma);
-+
-+      pa__done(m);
-+
-+      return -1;
-+}
-+
-+void pa__done(pa_module *m)
-+{
-+    struct userdata* u;
-+
-+    pa_assert(m);
-+
-+    if (!(u = m->userdata))
-+        return;
-+
-+    if (u->sink_input_new_hook_slot)
-+        pa_hook_slot_free(u->sink_input_new_hook_slot);
-+    if (u->sink_put_hook_slot)
-+        pa_hook_slot_free(u->sink_put_hook_slot);
-+    if (u->sink_unlink_slot)
-+        pa_hook_slot_free(u->sink_unlink_slot);
-+    if (u->sink_unlink_post_slot)
-+        pa_hook_slot_free(u->sink_unlink_post_slot);
-+    if (u->sink_input_move_start_slot)
-+        pa_hook_slot_free(u->sink_input_move_start_slot);
-+    if (u->sink_input_move_finish_slot)
-+        pa_hook_slot_free(u->sink_input_move_finish_slot);
-+    if (u->subscription)
-+        pa_subscription_free(u->subscription);
-+    if (u->protocol) {
-+        pa_native_protocol_remove_ext(u->protocol, m);
-+        pa_native_protocol_unref(u->protocol);
-+    }
-+    if (u->source_output_new_hook_slot)
-+        pa_hook_slot_free(u->source_output_new_hook_slot);
-+
-+    pa_xfree(u);
-+
-+
-+      pa_log_info("policy module is unloaded\n");
-+}
-diff --git a/src/pulse/ext-policy.c b/src/pulse/ext-policy.c
-new file mode 100644
-index 0000000..f3a3a8c
---- /dev/null
-+++ b/src/pulse/ext-policy.c
-@@ -0,0 +1,177 @@
-+/***
-+  This file is part of PulseAudio.
-+
-+  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 <pulse/context.h>
-+#include <pulse/gccmacro.h>
-+#include <pulse/xmalloc.h>
-+
-+#include <pulsecore/macro.h>
-+#include <pulsecore/pstream-util.h>
-+
-+#include "internal.h"
-+#include "operation.h"
-+#include "fork-detect.h"
-+
-+#include "ext-policy.h"
-+
-+enum {
-+    SUBCOMMAND_TEST,
-+    SUBCOMMAND_MONO,
-+    SUBCOMMAND_BALANCE,
-+};
-+
-+static void ext_policy_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-+    pa_operation *o = userdata;
-+    uint32_t version = PA_INVALID_INDEX;
-+
-+    pa_assert(pd);
-+    pa_assert(o);
-+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
-+
-+    if (!o->context)
-+        goto finish;
-+
-+    if (command != PA_COMMAND_REPLY) {
-+        if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
-+            goto finish;
-+
-+    } else if (pa_tagstruct_getu32(t, &version) < 0 ||
-+               !pa_tagstruct_eof(t)) {
-+
-+        pa_context_fail(o->context, PA_ERR_PROTOCOL);
-+        goto finish;
-+    }
-+
-+    if (o->callback) {
-+        pa_ext_policy_test_cb_t cb = (pa_ext_policy_test_cb_t) o->callback;
-+        cb(o->context, version, o->userdata);
-+    }
-+
-+finish:
-+    pa_operation_done(o);
-+    pa_operation_unref(o);
-+}
-+
-+pa_operation *pa_ext_policy_test(
-+        pa_context *c,
-+        pa_ext_device_manager_test_cb_t cb,
-+        void *userdata) {
-+
-+    uint32_t tag;
-+    pa_operation *o;
-+    pa_tagstruct *t;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
-+
-+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+    t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
-+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
-+    pa_tagstruct_puts(t, "module-policy");
-+    pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
-+    pa_pstream_send_tagstruct(c->pstream, t);
-+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_policy_test_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+    return o;
-+}
-+
-+pa_operation *pa_ext_policy_set_mono (
-+        pa_context *c,
-+        int enable,
-+        pa_context_success_cb_t cb,
-+        void *userdata) {
-+
-+    uint32_t tag;
-+    pa_operation *o = NULL;
-+    pa_tagstruct *t = NULL;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
-+
-+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+    t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
-+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
-+    pa_tagstruct_puts(t, "module-policy");
-+    pa_tagstruct_putu32(t, SUBCOMMAND_MONO);
-+    pa_tagstruct_put_boolean(t, !!enable);
-+
-+    pa_pstream_send_tagstruct(c->pstream, t);
-+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+    return o;
-+}
-+
-+pa_operation *pa_ext_policy_set_balance (
-+        pa_context *c,
-+        double *balance,
-+        pa_context_success_cb_t cb,
-+        void *userdata) {
-+
-+    uint32_t tag;
-+    pa_operation *o = NULL;
-+    pa_tagstruct *t = NULL;
-+    pa_cvolume cvol;
-+    pa_channel_map map;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
-+
-+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+    t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
-+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
-+    pa_tagstruct_puts(t, "module-policy");
-+    pa_tagstruct_putu32(t, SUBCOMMAND_BALANCE);
-+
-+    /* Prepare cvolume for transfer */
-+    pa_channel_map_init_stereo(&map);
-+    pa_cvolume_set(&cvol, map.channels, 65535);
-+
-+    pa_log_error ("balance = %f", *balance);
-+
-+    pa_cvolume_set_balance(&cvol, &map, *balance);
-+
-+    pa_log_error ("balance get = %f", pa_cvolume_get_balance(&cvol, &map));
-+
-+    pa_tagstruct_put_cvolume(t, &cvol);
-+
-+    pa_pstream_send_tagstruct(c->pstream, t);
-+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+    return o;
-+}
-+
-diff --git a/src/pulse/ext-policy.h b/src/pulse/ext-policy.h
-new file mode 100644
-index 0000000..ec62ead
---- /dev/null
-+++ b/src/pulse/ext-policy.h
-@@ -0,0 +1,61 @@
-+#ifndef foopulseextpolicyhfoo
-+#define foopulseextpolicyhfoo
-+
-+/***
-+  This file is part of PulseAudio.
-+
-+  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/context.h>
-+#include <pulse/version.h>
-+
-+/** \file
-+ *
-+ * Routines for controlling module-policy
-+ */
-+
-+PA_C_DECL_BEGIN
-+
-+/** Callback prototype for pa_ext_policy_test(). \since 0.9.21 */
-+typedef void (*pa_ext_policy_test_cb_t)(
-+        pa_context *c,
-+        uint32_t version,
-+        void *userdata);
-+
-+/** Test if this extension module is available in the server. \since 0.9.21 */
-+pa_operation *pa_ext_policy_test(
-+        pa_context *c,
-+        pa_ext_policy_test_cb_t cb,
-+        void *userdata);
-+
-+/** Enable the mono mode. \since 0.9.21 */
-+pa_operation *pa_ext_policy_set_mono (
-+        pa_context *c,
-+        int enable,
-+        pa_context_success_cb_t cb,
-+        void *userdata);
-+
-+/** Enable the balance mode. \since 0.9.21 */
-+pa_operation *pa_ext_policy_set_balance (
-+        pa_context *c,
-+        double *balance,
-+        pa_context_success_cb_t cb,
-+        void *userdata);
-+
-+PA_C_DECL_END
-+
-+#endif
-diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
-index dc3cddc..341abaa 100644
---- a/src/pulse/proplist.h
-+++ b/src/pulse/proplist.h
-@@ -65,6 +65,9 @@ PA_C_DECL_BEGIN
- /** For streams: logic role of this media. One of the strings "video", "music", "game", "event", "phone", "animation", "production", "a11y", "test" */
- #define PA_PROP_MEDIA_ROLE                     "media.role"
-+/** For streams: logic role of this media. One of the strings "auto", "phone" */
-+#define PA_PROP_MEDIA_POLICY                "media.policy"
-+
- /** For streams: the name of a filter that is desired, e.g.\ "echo-cancel" or "equalizer-sink". PulseAudio may choose to not apply the filter if it does not make sense (for example, applying echo-cancellation on a Bluetooth headset probably does not make sense. \since 1.0 */
- #define PA_PROP_FILTER_WANT                    "filter.want"
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0039-add-bluetooth-a2dp-aptx-codec-support-samsung.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0039-add-bluetooth-a2dp-aptx-codec-support-samsung.patch
deleted file mode 100644 (file)
index 1355048..0000000
+++ /dev/null
@@ -1,1024 +0,0 @@
-From: "vivian,zhang" <vivian.zhang@intel.com>
-Date: Tue, 18 Jun 2013 16:23:45 +0800
-Subject: add bluetooth a2dp aptx codec support - samsung
-
-Change-Id: I2c90198774c1e7d3e2ecb99f2dd365d56308f157
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- configure.ac                                      |  20 ++
- src/Makefile.am                                   |  27 +++
- src/modules/bluetooth/a2dp-codecs.h               |  39 ++++
- src/modules/bluetooth/bluetooth-util.h            | 183 +++++++++++++++++
- src/modules/bluetooth/bluez4-util.c               | 184 ++++++++++++++++-
- src/modules/bluetooth/module-bluetooth-discover.c |  37 ++++
- src/modules/bluetooth/module-bluez4-device.c      | 236 ++++++++++++++++++++++
- 7 files changed, 724 insertions(+), 2 deletions(-)
- create mode 100644 src/modules/bluetooth/bluetooth-util.h
-
-diff --git a/configure.ac b/configure.ac
-index 0e205d3..ebff16c 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1079,6 +1079,26 @@ else
- fi
- AC_SUBST(BLUETOOTH_HEADSET_BACKEND)
-+#### Bluetooth A2DP aptx codec support(optional) ####
-+AC_ARG_ENABLE([bt_a2dp_aptx],
-+    AS_HELP_STRING([--enable-bt-a2dp-aptx],[Enable optional Bluetooth A2DP aptx codec support(arm only)]),
-+        [
-+            case "${enableval}" in
-+                yes) bt_a2dp_aptx=yes ;;
-+                no) bt_a2dp_aptx=no ;;
-+                *) AC_MSG_ERROR(bad value ${enableval} for --enable-bt-a2dp-aptx) ;;
-+            esac
-+        ],
-+        [bt_a2dp_aptx=false])
-+if test "x${bt_a2dp_aptx}" == xyes ; then
-+      HAVE_BT_A2DP_APTX=1
-+else
-+      HAVE_BT_A2DP_APTX=0
-+fi
-+
-+AC_SUBST(HAVE_BT_A2DP_APTX)
-+AM_CONDITIONAL([HAVE_BT_A2DP_APTX], [test "x$HAVE_BT_A2DP_APTX" = x1])
-+
- #### UDEV support (optional) ####
- AC_ARG_ENABLE([udev],
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 4872dfd..3c062eb 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -2078,7 +2078,11 @@ module_bluetooth_policy_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
- module_bluetooth_discover_la_SOURCES = modules/bluetooth/module-bluetooth-discover.c
- module_bluetooth_discover_la_LDFLAGS = $(MODULE_LDFLAGS)
- module_bluetooth_discover_la_LIBADD = $(MODULE_LIBADD)
-+if HAVE_BT_A2DP_APTX
-+module_bluetooth_discover_la_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_APTX_SUPPORT
-+else
- module_bluetooth_discover_la_CFLAGS = $(AM_CFLAGS)
-+endif
- # Bluetooth BlueZ 4 sink / source
- module_bluez4_discover_la_SOURCES = modules/bluetooth/module-bluez4-discover.c
-@@ -2092,12 +2096,23 @@ libbluez4_util_la_SOURCES = \
-               modules/bluetooth/bluez4-util.h
- libbluez4_util_la_LDFLAGS = -avoid-version
- libbluez4_util_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS)
-+
-+if HAVE_BT_A2DP_APTX
-+libbluez4_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) -DBLUETOOTH_APTX_SUPPORT
-+else
- libbluez4_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
-+endif
- module_bluez4_device_la_SOURCES = modules/bluetooth/module-bluez4-device.c modules/bluetooth/rtp.h
- module_bluez4_device_la_LDFLAGS = $(MODULE_LDFLAGS)
- module_bluez4_device_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) $(SBC_LIBS) libbluez4-util.la
-+
-+if HAVE_BT_A2DP_APTX
-+module_bluez4_device_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(SBC_CFLAGS) \
-+                                    -DBLUETOOTH_APTX_SUPPORT
-+else
- module_bluez4_device_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(SBC_CFLAGS)
-+endif
- # Bluetooth BlueZ 5 sink / source
- libbluez5_util_la_SOURCES = \
-@@ -2108,7 +2123,12 @@ libbluez5_util_la_SOURCES = \
-               modules/bluetooth/hfaudioagent-@BLUETOOTH_HEADSET_BACKEND@.c
- libbluez5_util_la_LDFLAGS = -avoid-version
- libbluez5_util_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS)
-+
-+if HAVE_BT_A2DP_APTX
-+libbluez5_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) -DBLUETOOTH_APTX_SUPPORT
-+else
- libbluez5_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
-+endif
- module_bluez5_discover_la_SOURCES = modules/bluetooth/module-bluez5-discover.c
- module_bluez5_discover_la_LDFLAGS = $(MODULE_LDFLAGS)
-@@ -2120,6 +2140,13 @@ module_bluez5_device_la_LDFLAGS = $(MODULE_LDFLAGS)
- module_bluez5_device_la_LIBADD = $(MODULE_LIBADD) $(SBC_LIBS) libbluez5-util.la
- module_bluez5_device_la_CFLAGS = $(AM_CFLAGS) $(SBC_CFLAGS)
-+if HAVE_BT_A2DP_APTX
-+module_bluez5_device_la_CFLAGS = $(AM_CFLAGS) $(SBC_CFLAGS) \
-+                                    -DBLUETOOTH_APTX_SUPPORT
-+else
-+module_bluez5_device_la_CFLAGS = $(AM_CFLAGS) $(SBC_CFLAGS)
-+endif
-+
- # Apple Airtunes/RAOP
- module_raop_sink_la_SOURCES = modules/raop/module-raop-sink.c
- module_raop_sink_la_LDFLAGS = $(MODULE_LDFLAGS)
-diff --git a/src/modules/bluetooth/a2dp-codecs.h b/src/modules/bluetooth/a2dp-codecs.h
-index 51c796a..c94812b 100644
---- a/src/modules/bluetooth/a2dp-codecs.h
-+++ b/src/modules/bluetooth/a2dp-codecs.h
-@@ -27,6 +27,7 @@
- #define A2DP_CODEC_MPEG24             0x02
- #define A2DP_CODEC_ATRAC              0x03
-+#define A2DP_CODEC_NON_A2DP           0xFF
- #define SBC_SAMPLING_FREQ_16000               (1 << 3)
- #define SBC_SAMPLING_FREQ_32000               (1 << 2)
- #define SBC_SAMPLING_FREQ_44100               (1 << 1)
-@@ -67,6 +68,32 @@
- #define MAX_BITPOOL 64
- #define MIN_BITPOOL 2
-+/*#define APTX_CHANNEL_MODE_STEREO                    2 */
-+/*
-+ * aptX codec for Bluetooth only supports stereo mode with value 2
-+ * But we do have sink devices programmed to send capabilities with other channel mode support.
-+ * So to handle the case and keeping codec symmetry with SBC etc., we do define other channel mode,
-+ * and we always make sure to set configuration with APTX_CHANNEL_MODE_STEREO only.
-+ *
-+ * */
-+
-+#define APTX_CHANNEL_MODE_MONO                        (1 << 3)
-+#define APTX_CHANNEL_MODE_DUAL_CHANNEL        (1 << 2)
-+#define APTX_CHANNEL_MODE_STEREO              (1 << 1)
-+#define APTX_CHANNEL_MODE_JOINT_STEREO        1
-+
-+#define APTX_VENDOR_ID0               0x4F /*APTX codec ID 79*/
-+#define APTX_VENDOR_ID1               0x0
-+#define APTX_VENDOR_ID2               0x0
-+#define APTX_VENDOR_ID3               0x0
-+
-+#define APTX_CODEC_ID0                0x1
-+#define APTX_CODEC_ID1                0x0
-+
-+#define APTX_SAMPLING_FREQ_16000      (1 << 3)
-+#define APTX_SAMPLING_FREQ_32000      (1 << 2)
-+#define APTX_SAMPLING_FREQ_44100      (1 << 1)
-+#define APTX_SAMPLING_FREQ_48000      1
- #if __BYTE_ORDER == __LITTLE_ENDIAN
- typedef struct {
-@@ -89,6 +116,12 @@ typedef struct {
-       uint16_t bitrate;
- } __attribute__ ((packed)) a2dp_mpeg_t;
-+typedef struct {
-+      uint8_t vendor_id[4];
-+      uint8_t codec_id[2];
-+      uint8_t channel_mode:4;
-+      uint8_t frequency:4;
-+} __attribute__ ((packed)) a2dp_aptx_t;
- #elif __BYTE_ORDER == __BIG_ENDIAN
- typedef struct {
-@@ -110,6 +143,12 @@ typedef struct {
-       uint8_t frequency:6;
-       uint16_t bitrate;
- } __attribute__ ((packed)) a2dp_mpeg_t;
-+typedef struct {
-+      uint8_t vendor_id[4];
-+      uint8_t codec_id[2];
-+      uint8_t frequency:4;
-+      uint8_t channel_mode:4;
-+} __attribute__ ((packed)) a2dp_aptx_t;
- #else
- #error "Unknown byte order"
-diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h
-new file mode 100644
-index 0000000..859ad2d
---- /dev/null
-+++ b/src/modules/bluetooth/bluetooth-util.h
-@@ -0,0 +1,183 @@
-+#ifndef foobluetoothutilhfoo
-+#define foobluetoothutilhfoo
-+
-+/***
-+  This file is part of PulseAudio.
-+
-+  Copyright 2008-2009 Joao Paulo Rechi Vita
-+
-+  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 <dbus/dbus.h>
-+
-+#include <pulsecore/llist.h>
-+#include <pulsecore/macro.h>
-+
-+#define PA_BLUETOOTH_ERROR_NOT_SUPPORTED "org.bluez.Error.NotSupported"
-+
-+/* UUID copied from bluez/audio/device.h */
-+#define GENERIC_AUDIO_UUID      "00001203-0000-1000-8000-00805f9b34fb"
-+
-+#define HSP_HS_UUID             "00001108-0000-1000-8000-00805f9b34fb"
-+#define HSP_AG_UUID             "00001112-0000-1000-8000-00805f9b34fb"
-+
-+#define HFP_HS_UUID             "0000111e-0000-1000-8000-00805f9b34fb"
-+#define HFP_AG_UUID             "0000111f-0000-1000-8000-00805f9b34fb"
-+
-+#define ADVANCED_AUDIO_UUID     "0000110d-0000-1000-8000-00805f9b34fb"
-+
-+#define A2DP_SOURCE_UUID        "0000110a-0000-1000-8000-00805f9b34fb"
-+#define A2DP_SINK_UUID          "0000110b-0000-1000-8000-00805f9b34fb"
-+
-+#define HSP_MAX_GAIN 15
-+
-+typedef struct pa_bluetooth_uuid pa_bluetooth_uuid;
-+typedef struct pa_bluetooth_device pa_bluetooth_device;
-+typedef struct pa_bluetooth_discovery pa_bluetooth_discovery;
-+typedef struct pa_bluetooth_transport pa_bluetooth_transport;
-+
-+struct userdata;
-+
-+struct pa_bluetooth_uuid {
-+    char *uuid;
-+    PA_LLIST_FIELDS(pa_bluetooth_uuid);
-+};
-+
-+enum profile {
-+    PROFILE_A2DP,
-+    PROFILE_A2DP_SOURCE,
-+    PROFILE_HSP,
-+    PROFILE_HFGW,
-+    PROFILE_OFF
-+};
-+
-+#define PA_BLUETOOTH_PROFILE_COUNT PROFILE_OFF
-+
-+struct pa_bluetooth_hook_uuid_data {
-+    pa_bluetooth_device *device;
-+    const char *uuid;
-+};
-+
-+/* Hook data: pa_bluetooth_discovery pointer. */
-+typedef enum pa_bluetooth_hook {
-+    PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED, /* Call data: pa_bluetooth_device */
-+    PA_BLUETOOTH_HOOK_DEVICE_UUID_ADDED, /* Call data: pa_bluetooth_hook_uuid_data */
-+    PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED, /* Call data: pa_bluetooth_transport */
-+    PA_BLUETOOTH_HOOK_TRANSPORT_NREC_CHANGED, /* Call data: pa_bluetooth_transport */
-+    PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED, /* Call data: pa_bluetooth_transport */
-+    PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED, /* Call data: pa_bluetooth_transport */
-+    PA_BLUETOOTH_HOOK_MAX
-+} pa_bluetooth_hook_t;
-+
-+typedef enum pa_bluetooth_transport_state {
-+    PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED,
-+    PA_BLUETOOTH_TRANSPORT_STATE_IDLE, /* Connected but not playing */
-+    PA_BLUETOOTH_TRANSPORT_STATE_PLAYING
-+} pa_bluetooth_transport_state_t;
-+
-+struct pa_bluetooth_transport {
-+    pa_bluetooth_device *device;
-+    char *owner;
-+    char *path;
-+    enum profile profile;
-+    uint8_t codec;
-+    uint8_t *config;
-+    int config_size;
-+
-+    pa_bluetooth_transport_state_t state;
-+    bool nrec;
-+    uint16_t microphone_gain; /* Used for HSP/HFP */
-+    uint16_t speaker_gain; /* Used for HSP/HFP */
-+};
-+
-+/* This enum is shared among Audio, Headset, AudioSink, and AudioSource, although not all values are acceptable in all profiles */
-+typedef enum pa_bt_audio_state {
-+    PA_BT_AUDIO_STATE_INVALID = -1,
-+    PA_BT_AUDIO_STATE_DISCONNECTED,
-+    PA_BT_AUDIO_STATE_CONNECTING,
-+    PA_BT_AUDIO_STATE_CONNECTED,
-+    PA_BT_AUDIO_STATE_PLAYING
-+} pa_bt_audio_state_t;
-+
-+struct pa_bluetooth_device {
-+    pa_bluetooth_discovery *discovery;
-+    bool dead;
-+
-+    int device_info_valid;      /* 0: no results yet; 1: good results; -1: bad results ... */
-+
-+    /* Device information */
-+    char *name;
-+    char *path;
-+    pa_bluetooth_transport *transports[PA_BLUETOOTH_PROFILE_COUNT];
-+    int paired;
-+    char *alias;
-+    PA_LLIST_HEAD(pa_bluetooth_uuid, uuids);
-+    char *address;
-+    int class;
-+    int trusted;
-+
-+    /* Audio state */
-+    pa_bt_audio_state_t audio_state;
-+
-+    /* AudioSink, AudioSource, Headset and HandsfreeGateway states */
-+    pa_bt_audio_state_t profile_state[PA_BLUETOOTH_PROFILE_COUNT];
-+};
-+
-+pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core);
-+pa_bluetooth_discovery* pa_bluetooth_discovery_ref(pa_bluetooth_discovery *y);
-+void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *d);
-+
-+pa_bluetooth_device* pa_bluetooth_discovery_get_by_path(pa_bluetooth_discovery *d, const char* path);
-+pa_bluetooth_device* pa_bluetooth_discovery_get_by_address(pa_bluetooth_discovery *d, const char* address);
-+
-+bool pa_bluetooth_device_any_audio_connected(const pa_bluetooth_device *d);
-+
-+int pa_bluetooth_transport_acquire(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu);
-+void pa_bluetooth_transport_release(pa_bluetooth_transport *t);
-+
-+void pa_bluetooth_transport_set_microphone_gain(pa_bluetooth_transport *t, uint16_t value);
-+void pa_bluetooth_transport_set_speaker_gain(pa_bluetooth_transport *t, uint16_t value);
-+
-+pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *y, pa_bluetooth_hook_t hook);
-+
-+typedef enum pa_bt_form_factor {
-+    PA_BT_FORM_FACTOR_UNKNOWN,
-+    PA_BT_FORM_FACTOR_HEADSET,
-+    PA_BT_FORM_FACTOR_HANDSFREE,
-+    PA_BT_FORM_FACTOR_MICROPHONE,
-+    PA_BT_FORM_FACTOR_SPEAKER,
-+    PA_BT_FORM_FACTOR_HEADPHONE,
-+    PA_BT_FORM_FACTOR_PORTABLE,
-+    PA_BT_FORM_FACTOR_CAR,
-+    PA_BT_FORM_FACTOR_HIFI,
-+    PA_BT_FORM_FACTOR_PHONE,
-+} pa_bt_form_factor_t;
-+
-+pa_bt_form_factor_t pa_bluetooth_get_form_factor(uint32_t class);
-+const char *pa_bt_form_factor_to_string(pa_bt_form_factor_t ff);
-+
-+char *pa_bluetooth_cleanup_name(const char *name);
-+
-+bool pa_bluetooth_uuid_has(pa_bluetooth_uuid *uuids, const char *uuid);
-+const char *pa_bt_profile_to_string(enum profile profile);
-+
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+int pa_load_aptx(const char *aptx_lib_name);
-+int pa_unload_aptx(void);
-+void* pa_aptx_get_handle(void);
-+#endif
-+#endif
-diff --git a/src/modules/bluetooth/bluez4-util.c b/src/modules/bluetooth/bluez4-util.c
-index f047b73..7e7aed0 100644
---- a/src/modules/bluetooth/bluez4-util.c
-+++ b/src/modules/bluetooth/bluez4-util.c
-@@ -22,6 +22,9 @@
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+#include <dlfcn.h>
-+#endif
- #include <pulse/xmalloc.h>
-@@ -36,6 +39,9 @@
- #define ENDPOINT_PATH_HFP_HS "/MediaEndpoint/BlueZ4/HFPHS"
- #define ENDPOINT_PATH_A2DP_SOURCE "/MediaEndpoint/BlueZ4/A2DPSource"
- #define ENDPOINT_PATH_A2DP_SINK "/MediaEndpoint/BlueZ4/A2DPSink"
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+#define ENDPOINT_PATH_A2DP_APTX_SOURCE "/MediaEndpoint/Bluez4/A2DPSource_aptx"
-+#endif
- #define ENDPOINT_INTROSPECT_XML                                         \
-     DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                           \
-@@ -80,6 +86,56 @@ static pa_dbus_pending* send_and_add_to_pending(pa_bluez4_discovery *y, DBusMess
- static void found_adapter(pa_bluez4_discovery *y, const char *path);
- static pa_bluez4_device *found_device(pa_bluez4_discovery *y, const char* path);
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+static void *aptx_handle = NULL;
-+
-+int pa_unload_aptx(void)
-+{
-+      if (aptx_handle == NULL) {
-+              pa_log_warn("Unable to unload apt-X library");
-+              return -1;
-+      }
-+
-+      dlclose(aptx_handle);
-+      aptx_handle = NULL;
-+
-+      pa_log_debug("unloaded apt-X library successfully");
-+      return 0;
-+}
-+
-+int pa_load_aptx(const char *aptx_lib_name)
-+{
-+      char* lib_path = NULL ;
-+
-+        if(aptx_lib_name == NULL)
-+              return -1;
-+
-+        lib_path = pa_sprintf_malloc("%s/%s", PA_DLSEARCHPATH, aptx_lib_name);
-+
-+      if (!lib_path)
-+              return -1;
-+
-+      pa_log_info("aptx_lib_path = [%s]", lib_path);
-+
-+      aptx_handle = dlopen(lib_path, RTLD_LAZY);
-+      if (aptx_handle == NULL) {
-+              pa_log_warn("Unable to load apt-X library [%s]", dlerror());
-+              pa_xfree(lib_path);
-+              return -1;
-+      }
-+
-+      pa_log_debug("loaded apt-X library successfully");
-+      pa_xfree(lib_path);
-+
-+      return 0;
-+}
-+
-+void* pa_aptx_get_handle(void)
-+{
-+      return aptx_handle;
-+}
-+#endif
-+
- static pa_bluez4_audio_state_t audio_state_from_string(const char* value) {
-     pa_assert(value);
-@@ -835,6 +891,8 @@ static void register_endpoint(pa_bluez4_discovery *y, const char *path, const ch
-         uint8_t capability = 0;
-         pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capability, 1);
-     } else {
-+        pa_log_debug("register_endpoint: codec=%d[%s]", codec, codec==A2DP_CODEC_SBC ? "A2DP_CODEC_SBC" : codec==A2DP_CODEC_NON_A2DP ? "A2DP_CODEC_NON_A2DP" : "unknown");
-+        if (codec == A2DP_CODEC_SBC) {
-         a2dp_sbc_t capabilities;
-         capabilities.channel_mode = SBC_CHANNEL_MODE_MONO | SBC_CHANNEL_MODE_DUAL_CHANNEL |
-@@ -849,6 +907,23 @@ static void register_endpoint(pa_bluez4_discovery *y, const char *path, const ch
-         capabilities.max_bitpool = MAX_BITPOOL;
-         pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capabilities, sizeof(capabilities));
-+        } else if (codec == A2DP_CODEC_NON_A2DP ) {
-+          /* aptx */
-+            a2dp_aptx_t capabilities;
-+
-+            capabilities.vendor_id[0] = APTX_VENDOR_ID0;
-+            capabilities.vendor_id[1] = APTX_VENDOR_ID1;
-+            capabilities.vendor_id[2] = APTX_VENDOR_ID2;
-+            capabilities.vendor_id[3] = APTX_VENDOR_ID3;
-+
-+            capabilities.codec_id[0] = APTX_CODEC_ID0;
-+            capabilities.codec_id[1] = APTX_CODEC_ID1;
-+
-+            capabilities.channel_mode= APTX_CHANNEL_MODE_STEREO;
-+            capabilities.frequency= APTX_SAMPLING_FREQ_44100;
-+
-+            pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &capabilities, sizeof(capabilities));
-+        }
-     }
-     dbus_message_iter_close_container(&i, &d);
-@@ -857,6 +932,7 @@ static void register_endpoint(pa_bluez4_discovery *y, const char *path, const ch
- }
- static void found_adapter(pa_bluez4_discovery *y, const char *path) {
-+
-     DBusMessage *m;
-     pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Adapter", "GetProperties"));
-@@ -866,6 +942,10 @@ static void found_adapter(pa_bluez4_discovery *y, const char *path) {
-     register_endpoint(y, path, ENDPOINT_PATH_HFP_HS, HFP_HS_UUID);
-     register_endpoint(y, path, ENDPOINT_PATH_A2DP_SOURCE, A2DP_SOURCE_UUID);
-     register_endpoint(y, path, ENDPOINT_PATH_A2DP_SINK, A2DP_SINK_UUID);
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    if (aptx_handle)
-+        register_endpoint(y, path, ENDPOINT_PATH_A2DP_APTX_SOURCE, A2DP_SOURCE_UUID);
-+#endif
- }
- static void list_adapters(pa_bluez4_discovery *y) {
-@@ -1349,7 +1429,11 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
-         p = PA_BLUEZ4_PROFILE_HSP;
-     else if (dbus_message_has_path(m, ENDPOINT_PATH_HFP_HS))
-         p = PA_BLUEZ4_PROFILE_HFGW;
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    else if (dbus_message_has_path(m, ENDPOINT_PATH_A2DP_SOURCE) || dbus_message_has_path(m, ENDPOINT_PATH_A2DP_APTX_SOURCE))
-+#else
-     else if (dbus_message_has_path(m, ENDPOINT_PATH_A2DP_SOURCE))
-+#endif
-         p = PA_BLUEZ4_PROFILE_A2DP;
-     else
-         p = PA_BLUEZ4_PROFILE_A2DP_SOURCE;
-@@ -1475,6 +1559,84 @@ static uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode) {
-     }
- }
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+static DBusMessage *endpoint_select_configuration_for_aptx(DBusConnection *c, DBusMessage *m, void *userdata) {
-+    a2dp_aptx_t *cap;
-+    a2dp_aptx_t config;
-+    uint8_t *pconf = (uint8_t *) &config;
-+    int size;
-+    DBusMessage *r;
-+    DBusError e;
-+
-+    dbus_error_init(&e);
-+
-+    if (!dbus_message_get_args(m, &e, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &cap, &size, DBUS_TYPE_INVALID)) {
-+        pa_log("org.bluez.MediaEndpoint.SelectConfiguration: %s", e.message);
-+        dbus_error_free(&e);
-+        goto fail;
-+    }
-+
-+    pa_assert(size == sizeof(config));
-+
-+    memset(&config, 0, sizeof(config));
-+
-+    if (cap->vendor_id[0] == APTX_VENDOR_ID0 &&
-+        cap->vendor_id[1] == APTX_VENDOR_ID1 &&
-+        cap->vendor_id[2] == APTX_VENDOR_ID2 &&
-+        cap->vendor_id[3] == APTX_VENDOR_ID3 &&
-+         cap->codec_id[0] == APTX_CODEC_ID0  &&
-+         cap->codec_id[1] == APTX_CODEC_ID1  )
-+        pa_log_debug("A2DP_CODEC_NON_A2DP and this is APTX Codec");
-+    else {
-+        pa_log_debug("A2DP_CODEC_NON_A2DP but this is not APTX Codec");
-+        goto fail;
-+    }
-+
-+    memcpy(&config,cap, sizeof(config));
-+
-+/* The below code shuld be re-written by aptx */
-+/* And we should configure pulseaudio freq */
-+
-+    if (cap->frequency & APTX_SAMPLING_FREQ_44100)
-+        config.frequency = APTX_SAMPLING_FREQ_44100;
-+    else if (cap->frequency & APTX_SAMPLING_FREQ_48000)
-+        config.frequency = APTX_SAMPLING_FREQ_48000;
-+    else if (cap->frequency & APTX_SAMPLING_FREQ_32000)
-+        config.frequency = APTX_SAMPLING_FREQ_32000;
-+    else if (cap->frequency & APTX_SAMPLING_FREQ_16000)
-+        config.frequency = APTX_SAMPLING_FREQ_16000;
-+    else {
-+        pa_log_error("No aptx supported frequencies");
-+        goto fail;
-+    }
-+
-+    if (cap->channel_mode & APTX_CHANNEL_MODE_JOINT_STEREO)
-+        config.channel_mode = APTX_CHANNEL_MODE_STEREO;
-+    else if (cap->channel_mode & APTX_CHANNEL_MODE_STEREO)
-+        config.channel_mode = APTX_CHANNEL_MODE_STEREO;
-+    else if (cap->channel_mode & APTX_CHANNEL_MODE_DUAL_CHANNEL)
-+        config.channel_mode = APTX_CHANNEL_MODE_STEREO;
-+    else {
-+        pa_log_error("No aptx supported channel modes");
-+        goto fail;
-+    }
-+
-+    pa_assert_se(r = dbus_message_new_method_return(m));
-+
-+    pa_assert_se(dbus_message_append_args(
-+                                     r,
-+                                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pconf, size,
-+                                     DBUS_TYPE_INVALID));
-+
-+    return r;
-+
-+fail:
-+    pa_assert_se(r = (dbus_message_new_error(m, "org.bluez.MediaEndpoint.Error.InvalidArguments",
-+                                                        "Unable to select configuration")));
-+    return r;
-+}
-+#endif
-+
- static DBusMessage *endpoint_select_configuration(DBusConnection *c, DBusMessage *m, void *userdata) {
-     pa_bluez4_discovery *y = userdata;
-     a2dp_sbc_t *cap, config;
-@@ -1493,6 +1655,10 @@ static DBusMessage *endpoint_select_configuration(DBusConnection *c, DBusMessage
-         { 48000U, SBC_SAMPLING_FREQ_48000 }
-     };
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    if (dbus_message_has_path(m, A2DP_APTX_SOURCE_ENDPOINT))
-+        return endpoint_select_configuration_for_aptx(c ,m ,userdata);
-+#endif
-     dbus_error_init(&e);
-     if (!dbus_message_get_args(m, &e, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &cap, &size, DBUS_TYPE_INVALID)) {
-@@ -1614,8 +1780,13 @@ static DBusHandlerResult endpoint_handler(DBusConnection *c, DBusMessage *m, voi
-     dbus_error_init(&e);
--    if (!pa_streq(path, ENDPOINT_PATH_A2DP_SOURCE) && !pa_streq(path, ENDPOINT_PATH_A2DP_SINK)
--            && !pa_streq(path, ENDPOINT_PATH_HFP_AG) && !pa_streq(path, ENDPOINT_PATH_HFP_HS))
-+    if (!pa_streq(path, ENDPOINT_PATH_A2DP_SOURCE) &&
-+        !pa_streq(path, ENDPOINT_PATH_A2DP_SINK) &&
-+        !pa_streq(path, ENDPOINT_PATH_HFP_AG) &&
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+        !pa_streq(path, ENDPOINT_PATH_A2DP_APTX_SOURCE) &&
-+#endif
-+        !pa_streq(path, ENDPOINT_PATH_HFP_HS))
-         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
-@@ -1706,6 +1877,11 @@ pa_bluez4_discovery* pa_bluez4_discovery_get(pa_core *c) {
-     pa_assert_se(dbus_connection_register_object_path(conn, ENDPOINT_PATH_A2DP_SOURCE, &vtable_endpoint, y));
-     pa_assert_se(dbus_connection_register_object_path(conn, ENDPOINT_PATH_A2DP_SINK, &vtable_endpoint, y));
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    if (aptx_handle)
-+        pa_assert_se(dbus_connection_register_object_path(conn, ENDPOINT_PATH_A2DP_APTX_SOURCE, &vtable_endpoint, y));
-+#endif
-+
-     list_adapters(y);
-     return y;
-@@ -1754,6 +1930,10 @@ void pa_bluez4_discovery_unref(pa_bluez4_discovery *y) {
-         dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), ENDPOINT_PATH_HFP_HS);
-         dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), ENDPOINT_PATH_A2DP_SOURCE);
-         dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), ENDPOINT_PATH_A2DP_SINK);
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+        if (aptx_handle)
-+            dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), ENDPOINT_PATH_A2DP_APTX_SOURCE);
-+#endif
-         pa_dbus_remove_matches(
-             pa_dbus_connection_get(y->connection),
-             "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged'"
-diff --git a/src/modules/bluetooth/module-bluetooth-discover.c b/src/modules/bluetooth/module-bluetooth-discover.c
-index 0bcfcf9..e1dbec5 100644
---- a/src/modules/bluetooth/module-bluetooth-discover.c
-+++ b/src/modules/bluetooth/module-bluetooth-discover.c
-@@ -34,6 +34,17 @@ PA_MODULE_DESCRIPTION("Detect available Bluetooth daemon and load the correspond
- PA_MODULE_VERSION(PACKAGE_VERSION);
- PA_MODULE_LOAD_ONCE(true);
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+PA_MODULE_USAGE("aptx_lib_name=<name of aptx library name>");
-+#endif
-+
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+static const char* const valid_modargs[] = {
-+    "aptx_lib_name",
-+    NULL
-+};
-+#endif
-+
- struct userdata {
-     uint32_t bluez5_module_idx;
-     uint32_t bluez4_module_idx;
-@@ -43,8 +54,30 @@ int pa__init(pa_module* m) {
-     struct userdata *u;
-     pa_module *mm;
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    pa_modargs *ma = NULL;
-+    const char *aptx_lib_name = NULL;
-+#endif
-+
-     pa_assert(m);
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-+        pa_log("Failed to parse module arguments");
-+        goto fail;
-+    }
-+
-+    if (pa_modargs_get_value(ma, "async", NULL))
-+        pa_log_warn("The 'async' argument is deprecated and does nothing.");
-+
-+
-+    aptx_lib_name = pa_modargs_get_value(ma, "aptx_lib_name", NULL);
-+    if (aptx_lib_name)
-+        pa_load_aptx(aptx_lib_name);
-+    else
-+        pa_log("Failed to parse aptx_lib_name argument.");
-+#endif
-+
-     m->userdata = u = pa_xnew0(struct userdata, 1);
-     u->bluez5_module_idx = PA_INVALID_INDEX;
-     u->bluez4_module_idx = PA_INVALID_INDEX;
-@@ -83,5 +116,9 @@ void pa__done(pa_module* m) {
-     if (u->bluez4_module_idx != PA_INVALID_INDEX)
-         pa_module_unload_by_index(m->core, u->bluez4_module_idx, true);
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    pa_unload_aptx();
-+#endif
-+
-     pa_xfree(u);
- }
-diff --git a/src/modules/bluetooth/module-bluez4-device.c b/src/modules/bluetooth/module-bluez4-device.c
-index b0b12f8..eba92c6 100644
---- a/src/modules/bluetooth/module-bluez4-device.c
-+++ b/src/modules/bluetooth/module-bluez4-device.c
-@@ -29,6 +29,9 @@
- #include <math.h>
- #include <linux/sockios.h>
- #include <arpa/inet.h>
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+#include <dlfcn.h>
-+#endif
- #include <pulse/rtclock.h>
- #include <pulse/sample.h>
-@@ -107,6 +110,10 @@ struct a2dp_info {
-     bool sbc_initialized;                /* Keep track if the encoder is initialized */
-     size_t codesize, frame_length;       /* SBC Codesize, frame_length. We simply cache those values here */
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    pa_bool_t aptx_initialized;       /* Keep track if the encoder is initialized */
-+    void *aptx;                       /* Codec data */
-+#endif
-     void* buffer;                        /* Codec transfer buffer */
-     size_t buffer_size;                  /* Size of the buffer */
-@@ -207,6 +214,42 @@ enum {
- static int init_profile(struct userdata *u);
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+void* (*aptx_new)(short endian);
-+int (*aptx_encode)(void* _state, void* _pcmL, void* _pcmR, void* _buffer);
-+
-+const char *aptx_new_name = "NewAptxEnc";
-+const char *aptx_encode_name = "aptxbtenc_encodestereo";
-+
-+static pa_bool_t pa_load_aptx_sym(void *handle )
-+{
-+      if (!handle)
-+              return FALSE;
-+
-+      aptx_new = (void* (*)(short endian))dlsym(handle, aptx_new_name);
-+
-+      if (aptx_new) {
-+          pa_log_debug("Load Symbol(%s)", aptx_new_name);
-+        } else {
-+          pa_log_debug("Fail to Load Symbol(%s)", aptx_new_name);
-+          return FALSE;
-+      }
-+
-+      aptx_encode = (int (*)(void* _state, void* _pcmL, void* _pcmR,
-+                                void* _buffer))
-+                      dlsym(handle, "aptxbtenc_encodestereo");
-+
-+      if (aptx_encode) {
-+          pa_log_debug("Load Symbol(%s)", aptx_encode_name);
-+        } else {
-+          pa_log_debug("Fail to Load Symbol(%s)", aptx_encode_name);
-+          return FALSE;
-+        }
-+
-+      return TRUE;
-+}
-+#endif
-+
- /* from IO thread */
- static void a2dp_set_bitpool(struct userdata *u, uint8_t bitpool) {
-     struct a2dp_info *a2dp;
-@@ -859,6 +902,123 @@ static int a2dp_process_render(struct userdata *u) {
-     return ret;
- }
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+/* Run from IO thread */
-+static int a2dp_aptx_process_render(struct userdata *u) {
-+    struct a2dp_info *a2dp;
-+    size_t nbytes;
-+    void *d;
-+    const void *p;
-+    size_t to_write, to_encode;
-+    int ret = 0;
-+
-+    int pcmL[4],pcmR[4];
-+    int i=0;
-+    const short *mybuffer;
-+
-+    pa_assert(u);
-+    pa_assert(u->profile == PROFILE_A2DP);
-+    pa_assert(u->sink);
-+
-+    /* First, render some data */
-+    if (!u->write_memchunk.memblock)
-+        pa_sink_render_full(u->sink, u->write_block_size, &u->write_memchunk);
-+
-+    pa_assert(u->write_memchunk.length == u->write_block_size);
-+
-+    a2dp_prepare_buffer(u);
-+
-+    a2dp = &u->a2dp;
-+
-+    /* Try to create a packet of the full MTU */
-+    p = (const uint8_t*) pa_memblock_acquire(u->write_memchunk.memblock) + u->write_memchunk.index;
-+    to_encode = u->write_memchunk.length;
-+
-+    d = (uint8_t*) a2dp->buffer ;
-+    to_write = a2dp->buffer_size;
-+
-+    while (PA_LIKELY(to_encode > 0 && to_write > 0)) {
-+        size_t written;
-+        ssize_t encoded;
-+
-+        mybuffer=(uint8_t *)p;
-+
-+        for (i = 0; i < 4; i += 1) {
-+           pcmL[i] = mybuffer[2*i];
-+           pcmR[i] = mybuffer[2*i+1];
-+        }
-+      /*(8 audio samples)16 bytes of audo data encoded to 4 bytes*/
-+      aptx_encode(a2dp->aptx, pcmL, pcmR, (short*)d);
-+
-+        encoded=16;
-+        written=4;
-+
-+        pa_assert_fp((size_t) encoded <= to_encode);
-+        pa_assert_fp((size_t) written <= to_write);
-+
-+        p = (const uint8_t*) p + encoded;
-+        to_encode -= encoded;
-+
-+        d = (uint8_t*) d + written;
-+        to_write -= written;
-+
-+    }
-+
-+    pa_memblock_release(u->write_memchunk.memblock);
-+
-+    pa_assert(to_encode == 0);
-+
-+    PA_ONCE_BEGIN {
-+        pa_log_debug("Using APTX encoder implementation");
-+    } PA_ONCE_END;
-+
-+    nbytes = (uint8_t*) d - (uint8_t*) a2dp->buffer;
-+
-+    for (;;) {
-+        ssize_t l;
-+
-+        l = pa_write(u->stream_fd, a2dp->buffer, nbytes, &u->stream_write_type);
-+
-+        pa_assert(l != 0);
-+
-+        if (l < 0) {
-+
-+            if (errno == EINTR)
-+                /* Retry right away if we got interrupted */
-+                continue;
-+
-+            else if (errno == EAGAIN)
-+                /* Hmm, apparently the socket was not writable, give up for now */
-+                break;
-+
-+            pa_log_error("Failed to write data to socket: %s", pa_cstrerror(errno));
-+            ret  = -1;
-+            break;
-+        }
-+
-+        pa_assert((size_t) l <= nbytes);
-+
-+        if ((size_t) l != nbytes) {
-+            pa_log_warn("Wrote memory block to socket only partially! %llu written, wanted to write %llu.",
-+                        (unsigned long long) l,
-+                        (unsigned long long) nbytes);
-+            ret = -1;
-+            break;
-+        }
-+
-+        u->write_index += (uint64_t) u->write_memchunk.length;
-+        pa_memblock_unref(u->write_memchunk.memblock);
-+        pa_memchunk_reset(&u->write_memchunk);
-+
-+        ret = 1;
-+
-+        break;
-+    }
-+
-+    return ret;
-+}
-+#endif
-+
- static int a2dp_process_push(struct userdata *u) {
-     int ret = 0;
-     pa_memchunk memchunk;
-@@ -1104,8 +1264,13 @@ static void thread_func(void *userdata) {
-                         u->started_at = pa_rtclock_now();
-                     if (u->profile == PA_BLUEZ4_PROFILE_A2DP) {
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+                        if ((n_written = a2dp_aptx_process_render(u)) < 0)
-+                                goto io_fail;
-+#else
-                         if ((n_written = a2dp_process_render(u)) < 0)
-                             goto io_fail;
-+#endif
-                     } else {
-                         if ((n_written = hsp_process_render(u)) < 0)
-                             goto io_fail;
-@@ -1689,14 +1854,73 @@ static int add_source(struct userdata *u) {
-     return 0;
- }
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+/* should be implemeted */
-+static int bt_transport_config_a2dp_for_aptx(struct userdata *u) {
-+    //const pa_bluetooth_transport *t;
-+    struct a2dp_info *a2dp = &u->a2dp;
-+    //a2dp_sbc_t *config;
-+
-+    //t = pa_bluetooth_discovery_get_transport(u->discovery, u->transport);
-+    //pa_assert(t);
-+
-+    //config = (a2dp_sbc_t *) t->config;
-+
-+    u->sample_spec.format = PA_SAMPLE_S16LE;
-+
-+    if (!a2dp->aptx_initialized){
-+      #if __BYTE_ORDER==__LITTLE_ENDIAN
-+              a2dp->aptx = aptx_new(1);
-+      #elif __BYTE_ORDER==__BIG_ENDIAN
-+              a2dp->aptx = aptx_new(0);
-+      #else
-+              #error "Unknown byte order"
-+      #endif
-+              a2dp->aptx_initialized = TRUE;
-+    }
-+
-+    pa_log_debug("aptx Encoder is intialized !!");
-+
-+    u->write_block_size =(size_t)(u->write_link_mtu/(size_t)16) *16*4 ;
-+    u->read_block_size =(size_t)(u->read_link_mtu/(size_t)16) *16*4 ;
-+
-+    pa_log_info("APTX parameters write_block_size(%d),write_link_mtu(%d)",u->write_block_size,u->write_link_mtu);
-+    pa_log_info("APTX parameters read_block_size(%d),read_link_mtu(%d)",u->read_block_size,u->read_link_mtu);
-+
-+    return 0;
-+}
-+#endif
-+
- static void bt_transport_config_a2dp(struct userdata *u) {
-     const pa_bluez4_transport *t;
-     struct a2dp_info *a2dp = &u->a2dp;
-     a2dp_sbc_t *config;
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    a2dp_aptx_t *aptx_config;
-+#endif
-     t = u->transport;
-     pa_assert(t);
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    if (t->codec == A2DP_CODEC_NON_A2DP) {
-+        aptx_config = (a2dp_aptx_t *) t->config;
-+        if (aptx_config->vendor_id[0] == APTX_VENDOR_ID0 &&
-+            aptx_config->vendor_id[1] == APTX_VENDOR_ID1 &&
-+            aptx_config->vendor_id[2] == APTX_VENDOR_ID2 &&
-+            aptx_config->vendor_id[3] == APTX_VENDOR_ID3 &&
-+            aptx_config->codec_id[0] == APTX_CODEC_ID0  &&
-+            aptx_config->codec_id[1] == APTX_CODEC_ID1  ){
-+            pa_log("A2DP_CODEC_NON_A2DP and this is APTX Codec");
-+
-+            return bt_transport_config_a2dp_for_aptx(u);
-+        } else {
-+            pa_log("A2DP_CODEC_NON_A2DP but this is not APTX Codec");
-+            return -1;
-+        }
-+    }
-+#endif
-+
-     config = (a2dp_sbc_t *) t->config;
-     u->sample_spec.format = PA_SAMPLE_S16LE;
-@@ -2424,6 +2648,9 @@ int pa__init(pa_module *m) {
-     struct userdata *u;
-     const char *address, *path;
-     pa_bluez4_device *device;
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    void *handle;
-+#endif
-     pa_assert(m);
-@@ -2524,6 +2751,15 @@ int pa__init(pa_module *m) {
-     u->msg->parent.process_msg = device_process_msg;
-     u->msg->card = u->card;
-+#ifdef BLUETOOTH_APTX_SUPPORT
-+    handle = pa_aptx_get_handle();
-+
-+    if (handle) {
-+        pa_log_debug("Aptx Library loaded\n");
-+        pa_load_aptx_sym(handle);
-+    }
-+#endif
-+
-     if (u->profile != PA_BLUEZ4_PROFILE_OFF)
-         if (init_profile(u) < 0)
-             goto off;
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0040-create-pa_ready-file-samsung.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0040-create-pa_ready-file-samsung.patch
deleted file mode 100644 (file)
index 191e70e..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Thu, 8 Aug 2013 11:23:38 +0300
-Subject: create pa_ready file - samsung
-
-Change-Id: I2146599f2e814be064864f8ca76879b761642f11
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/daemon/main.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/src/daemon/main.c b/src/daemon/main.c
-index e01371e..74cb45f 100644
---- a/src/daemon/main.c
-+++ b/src/daemon/main.c
-@@ -38,6 +38,8 @@
- #include <sys/types.h>
- #include <sys/stat.h>
-+#include <fcntl.h>
-+
- #ifdef HAVE_SYS_MMAN_H
- #include <sys/mman.h>
- #endif
-@@ -101,6 +103,7 @@
- #include "ltdl-bind-now.h"
- #include "server-lookup.h"
-+#define PA_READY "/tmp/.pa_ready"
- #ifdef HAVE_LIBWRAP
- /* Only one instance of these variables */
- int allow_severity = LOG_INFO;
-@@ -1145,6 +1148,8 @@ int main(int argc, char *argv[]) {
- #endif
-     pa_log_info(_("Daemon startup complete."));
-+    /* broadcast if we're ready */
-+    creat(PA_READY, 0644);
-     retval = 0;
-     if (pa_mainloop_run(mainloop, &retval) < 0)
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0041-set-alsa-suspend-timeout-to-zero-samsung.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0041-set-alsa-suspend-timeout-to-zero-samsung.patch
deleted file mode 100644 (file)
index 9c6c9a4..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Thu, 8 Aug 2013 11:24:25 +0300
-Subject: set alsa suspend timeout to zero - samsung
-
-Change-Id: Ie7c93c727d878226189f751efbd6e088ece7f36f
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/alsa/alsa-sink.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
-index 5a41cf6..03babb3 100644
---- a/src/modules/alsa/alsa-sink.c
-+++ b/src/modules/alsa/alsa-sink.c
-@@ -60,6 +60,7 @@
- #include "alsa-util.h"
- #include "alsa-sink.h"
-+#define ALSA_SUSPEND_ON_IDLE_TIMEOUT  "0"
- /* #define DEBUG_TIMING */
- #define DEFAULT_DEVICE "default"
-@@ -2275,6 +2276,9 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
-     pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
-     pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial"));
-+    /* Set Suspend timeout to ZERO to avoid noise */
-+    pa_log_info("Set suspend-on-idle timeout to ZERO to avoid noise");
-+    pa_proplist_sets(data.proplist, "module-suspend-on-idle.timeout", ALSA_SUSPEND_ON_IDLE_TIMEOUT);
-     if (mapping) {
-         pa_proplist_sets(data.proplist, PA_PROP_DEVICE_PROFILE_NAME, mapping->name);
-         pa_proplist_sets(data.proplist, PA_PROP_DEVICE_PROFILE_DESCRIPTION, mapping->description);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0042-cope-with-possible-infinite-waiting-in-startup-samsu.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0042-cope-with-possible-infinite-waiting-in-startup-samsu.patch
deleted file mode 100644 (file)
index 4e91da4..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Thu, 8 Aug 2013 11:27:44 +0300
-Subject: cope with possible infinite waiting in startup - samsung
-
-Change-Id: Ie7c74131e267f44324f031a953c15f81b0c31a07
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/core-util.c | 19 ++++++++++++++++++-
- 1 file changed, 18 insertions(+), 1 deletion(-)
-
-diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
-index 0d9e354..1256a1e 100644
---- a/src/pulsecore/core-util.c
-+++ b/src/pulsecore/core-util.c
-@@ -1698,6 +1698,7 @@ static char* make_random_dir(mode_t m) {
-     char *fn;
-     size_t pathlen;
-+    srand (time(NULL));
-     fn = pa_sprintf_malloc("%s" PA_PATH_SEP "pulse-XXXXXXXXXXXX", pa_get_temp_dir());
-     pathlen = strlen(fn);
-@@ -1763,6 +1764,7 @@ static int make_random_dir_and_link(mode_t m, const char *k) {
- char *pa_get_runtime_dir(void) {
-     char *d, *k = NULL, *p = NULL, *t = NULL, *mid;
-     mode_t m;
-+    int retry_count = 100;
-     /* The runtime directory shall contain dynamic data that needs NOT
-      * to be kept across reboots and is usually private to the user,
-@@ -1823,6 +1825,21 @@ char *pa_get_runtime_dir(void) {
-     for (;;) {
-         /* OK, first let's check if the "runtime" symlink already exists */
-+        /* FIXME: This is recovery routine for infinite waiting issue such as below situation.
-+         * eg. 50f64052a5dbbe087c11dfac4effb63c-runtime -> /tmp/pulse-LDK8gTL6Dh9N
-+               50f64052a5dbbe087c11dfac4effb63c-runtime.tmp -> /tmp/pulse-cDM1bQhObZ7O */
-+        if (retry_count-- == 0) {
-+            pa_log_error ("retry is over....do cleanup");
-+
-+            /* Remove original file */
-+            unlink (k);
-+
-+            /* Remove original.tmp file */
-+            t = pa_sprintf_malloc("%s.tmp", k);
-+            unlink (t);
-+            pa_xfree(t);
-+            t = NULL;
-+        }
-         p = pa_readlink(k);
-         if (!p) {
-@@ -3297,7 +3314,7 @@ const char *pa_get_temp_dir(void) {
-         pa_is_path_absolute(t))
-         return t;
--    return "/tmp";
-+    return "/tmp/pulseaudio";
- }
- int pa_open_cloexec(const char *fn, int flags, mode_t mode) {
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0043-use-udev-only-for-usb-devices-samsung.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0043-use-udev-only-for-usb-devices-samsung.patch
deleted file mode 100644 (file)
index d989b3f..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Thu, 8 Aug 2013 11:28:39 +0300
-Subject: use udev only for usb devices - samsung
-
-Change-Id: Ia8cd2f5eb5ebe5248af11906c67d572ede133b33
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- configure.ac                        | 14 +++++++++++++-
- src/modules/alsa/module-alsa-card.c |  7 +++++++
- src/modules/module-udev-detect.c    | 17 +++++++++++++++++
- 3 files changed, 37 insertions(+), 1 deletion(-)
-
-diff --git a/configure.ac b/configure.ac
-index ebff16c..13c8f6c 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1115,8 +1115,18 @@ AC_SUBST(HAVE_UDEV)
- AM_CONDITIONAL([HAVE_UDEV], [test "x$HAVE_UDEV" = x1])
- AS_IF([test "x$HAVE_UDEV" = "x1"], AC_DEFINE([HAVE_UDEV], 1, [Have UDEV.]))
--#### HAL compat support (optional, dependent on UDEV) ####
-+#### udev for usb _only_ support (optional, dependant on UDEV) ####
-+AC_ARG_ENABLE([udev_with_usb_only],
-+    AS_HELP_STRING([--enable-udev-with-usb-only],[Enable UDEV with only USB support]))
-+
-+AS_IF([test "x$enable_udev_with_usb_only" != "xyes"],
-+    [AS_IF([test "x$HAVE_UDEV" = "x1"], HAVE_UDEV_ONLY_USB=0, HAVE_UDEV_ONLY_USB=1)],
-+    HAVE_UDEV_ONLY_USB=1)
-+AM_CONDITIONAL([HAVE_UDEV_ONLY_USB], [test "x$HAVE_UDEV_ONLY_USB" = x1])
-+AS_IF([test "x$HAVE_UDEV_ONLY_USB" = "x1"], AC_DEFINE([HAVE_UDEV_ONLY_USB], 1, [Have usb only with udev.]))
-+
-+#### HAL compat support (optional, dependent on UDEV) ####
- AC_ARG_ENABLE([hal-compat],
-     AS_HELP_STRING([--disable-hal-compat],[Disable optional HAL->udev transition compatibility support]))
-@@ -1511,6 +1521,7 @@ AS_IF([test "x$HAVE_SYSTEMD_JOURNAL" = "x1"], ENABLE_SYSTEMD_JOURNAL=yes, ENABLE
- AS_IF([test "x$HAVE_BLUEZ_4" = "x1"], ENABLE_BLUEZ_4=yes, ENABLE_BLUEZ_4=no)
- AS_IF([test "x$HAVE_BLUEZ_5" = "x1"], ENABLE_BLUEZ_5=yes, ENABLE_BLUEZ_5=no)
- AS_IF([test "x$HAVE_HAL_COMPAT" = "x1"], ENABLE_HAL_COMPAT=yes, ENABLE_HAL_COMPAT=no)
-+AS_IF([test "x$HAVE_UDEV_ONLY_USB" = "x1"], ENABLE_UDEV_ONLY_USB=yes, ENABLE_UDEV_ONLY_USB=no)
- AS_IF([test "x$HAVE_TCPWRAP" = "x1"], ENABLE_TCPWRAP=yes, ENABLE_TCPWRAP=no)
- AS_IF([test "x$HAVE_LIBSAMPLERATE" = "x1"], ENABLE_LIBSAMPLERATE=yes, ENABLE_LIBSAMPLERATE=no)
- AS_IF([test "x$HAVE_IPV6" = "x1"], ENABLE_IPV6=yes, ENABLE_IPV6=no)
-@@ -1566,6 +1577,7 @@ echo "
-         headset backed:            ${BLUETOOTH_HEADSET_BACKEND}
-     Enable udev:                   ${ENABLE_UDEV}
-       Enable HAL->udev compat:     ${ENABLE_HAL_COMPAT}
-+      Enable udev usb only:        ${ENABLE_UDEV_ONLY_USB}
-     Enable systemd login:          ${ENABLE_SYSTEMD}
-     Enable systemd journal:        ${ENABLE_SYSTEMD_JOURNAL}
-     Enable TCP Wrappers:           ${ENABLE_TCPWRAP}
-diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
-index cf54c0f..1e63230 100644
---- a/src/modules/alsa/module-alsa-card.c
-+++ b/src/modules/alsa/module-alsa-card.c
-@@ -678,6 +678,13 @@ int pa__init(pa_module *m) {
-         u->use_ucm = false;
- #ifdef HAVE_UDEV
-         fn = pa_udev_get_property(u->alsa_card_index, "PULSE_PROFILE_SET");
-+#ifdef ENABLE_UDEV_ONLY_USB
-+      pa_log("PULSE_PROFILE_SET = %s", fn);
-+      if (fn == NULL) {
-+            fn = strdup ("tizen_usb.conf");
-+          pa_log("(new) PULSE_PROFILE_SET = %s", fn);
-+    }
-+#endif
- #endif
-         if (pa_modargs_get_value(u->modargs, "profile_set", NULL)) {
-diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c
-index c28c867..1e8fb06 100644
---- a/src/modules/module-udev-detect.c
-+++ b/src/modules/module-udev-detect.c
-@@ -464,6 +464,23 @@ static void process_device(struct userdata *u, struct udev_device *dev) {
-         return;
-     }
-+    pa_log_debug ("devpath = %s", udev_device_get_devpath(dev));
-+    pa_log_debug ("subsystem = %s", udev_device_get_subsystem(dev));
-+    pa_log_debug ("devtype = %s", udev_device_get_devtype(dev));
-+    pa_log_debug ("syspath = %s", udev_device_get_syspath(dev));
-+    pa_log_debug ("sysname = %s", udev_device_get_sysname(dev));
-+    pa_log_debug ("sysnum = %s", udev_device_get_sysnum(dev));
-+    pa_log_debug ("devnode = %s", udev_device_get_devnode(dev));
-+    pa_log_debug ("parent subsystem = %s", udev_device_get_subsystem(udev_device_get_parent(dev)));
-+
-+#ifdef ENABLE_UDEV_ONLY_USB
-+    /* If parent's subsystem is not USB, return */
-+    if (!pa_streq(udev_device_get_subsystem(udev_device_get_parent(dev)), "usb")) {
-+        pa_log_debug("Ignoring %s, because it's parent subsystem is not a USB.", udev_device_get_devpath(dev));
-+        return;
-+    }
-+#endif
-+
-     action = udev_device_get_action(dev);
-     if (action && pa_streq(action, "remove"))
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0044-fixes-and-improvements-to-makefile-and-configure-in-.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0044-fixes-and-improvements-to-makefile-and-configure-in-.patch
deleted file mode 100644 (file)
index 0cb735b..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Fri, 7 Mar 2014 17:49:42 +0200
-Subject: fixes and improvements to makefile and configure in - samsung
-
-Change-Id: Ic2338a8382fe45f9d509537950592c9c4aa83606
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- configure.ac    | 14 +++++++++++++-
- src/Makefile.am | 28 +++++++++-------------------
- 2 files changed, 22 insertions(+), 20 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index 13c8f6c..870375f 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1539,6 +1539,11 @@ AS_IF([test "x$HAVE_ESOUND" = "x1" -a "x$USE_PER_USER_ESOUND_SOCKET" = "x1"], EN
- AS_IF([test "x$HAVE_GCOV" = "x1"], ENABLE_GCOV=yes, ENABLE_GCOV=no)
- AS_IF([test "x$HAVE_LIBCHECK" = "x1"], ENABLE_TESTS=yes, ENABLE_TESTS=no)
- AS_IF([test "x$enable_legacy_database_entry_format" != "xno"], ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=yes, ENABLE_LEGACY_DATABASE_ENTRY_FORMAT=no)
-+AS_IF([test "x$USE_SAMSUNG_POLICY" = "x1"], ENABLE_SAMSUNG_POLICY=yes, ENABLE_SAMSUNG_POLICY=no)
-+AS_IF([test "x$USE_DLOG" = "x1"], ENABLE_DLOG=yes, ENABLE_DLOG=no)
-+AS_IF([test "x$USE_PM_LOCK" = "x1"], ENABLE_PM_LOCK=yes, ENABLE_PM_LOCK=no)
-+AS_IF([test "x$USE_BT_PROFILE_SET" = "x1"], ENABLE_BT_PROFILE_SET=yes, ENABLE_BT_PROFILE_SET=no)
-+AS_IF([test "x$HAVE_BT_A2DP_APTX" = "x1"], HAVE_BT_A2DP_APTX=yes, HAVE_BT_A2DP_APTX=no)
- echo "
-  ---{ $PACKAGE_NAME $VERSION }---
-@@ -1577,7 +1582,6 @@ echo "
-         headset backed:            ${BLUETOOTH_HEADSET_BACKEND}
-     Enable udev:                   ${ENABLE_UDEV}
-       Enable HAL->udev compat:     ${ENABLE_HAL_COMPAT}
--      Enable udev usb only:        ${ENABLE_UDEV_ONLY_USB}
-     Enable systemd login:          ${ENABLE_SYSTEMD}
-     Enable systemd journal:        ${ENABLE_SYSTEMD_JOURNAL}
-     Enable TCP Wrappers:           ${ENABLE_TCPWRAP}
-@@ -1604,6 +1608,14 @@ echo "
-     Preopened modules:             ${PREOPEN_MODS}
-     Legacy Database Entry Support: ${ENABLE_LEGACY_DATABASE_ENTRY_FORMAT}
-+
-+    Tizen
-+      samsung policy:              ${ENABLE_SAMSUNG_POLICY}
-+      dlog:                        ${ENABLE_DLOG}
-+      pmapi:                       ${ENABLE_PM_LOCK}
-+      bluetooth profile set:       ${ENABLE_BT_PROFILE_SET}
-+      bluetooth aptx codec:        ${HAVE_BT_A2DP_APTX}
-+      udev with usb only:          ${ENABLE_UDEV_ONLY_USB}
- "
- if test "${ENABLE_SPEEX}" = "no" && test "${ENABLE_WEBRTC}" = "no" && test "${ENABLE_ADRIAN_EC}" = "no" ; then
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 3c062eb..a60b5bf 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -2078,10 +2078,9 @@ module_bluetooth_policy_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
- module_bluetooth_discover_la_SOURCES = modules/bluetooth/module-bluetooth-discover.c
- module_bluetooth_discover_la_LDFLAGS = $(MODULE_LDFLAGS)
- module_bluetooth_discover_la_LIBADD = $(MODULE_LIBADD)
--if HAVE_BT_A2DP_APTX
--module_bluetooth_discover_la_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_APTX_SUPPORT
--else
- module_bluetooth_discover_la_CFLAGS = $(AM_CFLAGS)
-+if HAVE_BT_A2DP_APTX
-+module_bluetooth_discover_la_CFLAGS += -DBLUETOOTH_APTX_SUPPORT
- endif
- # Bluetooth BlueZ 4 sink / source
-@@ -2096,22 +2095,17 @@ libbluez4_util_la_SOURCES = \
-               modules/bluetooth/bluez4-util.h
- libbluez4_util_la_LDFLAGS = -avoid-version
- libbluez4_util_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS)
--
--if HAVE_BT_A2DP_APTX
--libbluez4_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) -DBLUETOOTH_APTX_SUPPORT
--else
- libbluez4_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
-+if HAVE_BT_A2DP_APTX
-+libbluez4_util_la_CFLAGS += -DBLUETOOTH_APTX_SUPPORT
- endif
- module_bluez4_device_la_SOURCES = modules/bluetooth/module-bluez4-device.c modules/bluetooth/rtp.h
- module_bluez4_device_la_LDFLAGS = $(MODULE_LDFLAGS)
- module_bluez4_device_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) $(SBC_LIBS) libbluez4-util.la
--
--if HAVE_BT_A2DP_APTX
--module_bluez4_device_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(SBC_CFLAGS) \
--                                    -DBLUETOOTH_APTX_SUPPORT
--else
- module_bluez4_device_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(SBC_CFLAGS)
-+if HAVE_BT_A2DP_APTX
-+module_bluez4_device_la_CFLAGS += -DBLUETOOTH_APTX_SUPPORT
- endif
- # Bluetooth BlueZ 5 sink / source
-@@ -2123,11 +2117,10 @@ libbluez5_util_la_SOURCES = \
-               modules/bluetooth/hfaudioagent-@BLUETOOTH_HEADSET_BACKEND@.c
- libbluez5_util_la_LDFLAGS = -avoid-version
- libbluez5_util_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS)
-+libbluez5_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
- if HAVE_BT_A2DP_APTX
--libbluez5_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) -DBLUETOOTH_APTX_SUPPORT
--else
--libbluez5_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
-+libbluez5_util_la_CFLAGS += -DBLUETOOTH_APTX_SUPPORT
- endif
- module_bluez5_discover_la_SOURCES = modules/bluetooth/module-bluez5-discover.c
-@@ -2141,10 +2134,7 @@ module_bluez5_device_la_LIBADD = $(MODULE_LIBADD) $(SBC_LIBS) libbluez5-util.la
- module_bluez5_device_la_CFLAGS = $(AM_CFLAGS) $(SBC_CFLAGS)
- if HAVE_BT_A2DP_APTX
--module_bluez5_device_la_CFLAGS = $(AM_CFLAGS) $(SBC_CFLAGS) \
--                                    -DBLUETOOTH_APTX_SUPPORT
--else
--module_bluez5_device_la_CFLAGS = $(AM_CFLAGS) $(SBC_CFLAGS)
-+module_bluez5_device_la_CFLAGS += -DBLUETOOTH_APTX_SUPPORT
- endif
- # Apple Airtunes/RAOP
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0045-fix-warning-in-gconf-helper.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0045-fix-warning-in-gconf-helper.patch
deleted file mode 100644 (file)
index b89ec5a..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Tue, 11 Mar 2014 12:47:52 +0200
-Subject: fix warning in gconf helper
-
-Change-Id: Id75cd24cfd1c0d62d4c227b6715dc0d9d5ea6b1f
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/gconf/gconf-helper.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/src/modules/gconf/gconf-helper.c b/src/modules/gconf/gconf-helper.c
-index fbd8cfd..4681748 100644
---- a/src/modules/gconf/gconf-helper.c
-+++ b/src/modules/gconf/gconf-helper.c
-@@ -99,7 +99,9 @@ int main(int argc, char *argv[]) {
-     GConfClient *client;
-     GSList *modules, *m;
-+#if !defined(GLIB_VERSION_2_36)
-     g_type_init();
-+#endif
-     if (!(client = gconf_client_get_default()))
-         goto fail;
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0046-volume-ramp-add-client-api-support-for-volume-rampin.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0046-volume-ramp-add-client-api-support-for-volume-rampin.patch
deleted file mode 100644 (file)
index 9cc07b6..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@helsinki.fi>
-Date: Wed, 8 Aug 2012 11:14:40 +0300
-Subject: volume ramp: add client api support for volume ramping
-
-Change-Id: I6afc7540af68400db54eec258bdf4a80c311bb69
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/map-file                    |  3 ++
- src/pulse/introspect.c          | 74 +++++++++++++++++++++++++++++++++++++
- src/pulse/introspect.h          |  9 +++++
- src/pulse/stream.c              |  6 ++-
- src/pulsecore/native-common.h   |  3 ++
- src/pulsecore/pdispatch.c       |  2 +
- src/pulsecore/protocol-native.c | 81 ++++++++++++++++++++++++++++++++++++++++-
- src/pulsecore/tagstruct.c       | 74 +++++++++++++++++++++++++++++++++++++
- src/pulsecore/tagstruct.h       |  3 ++
- 9 files changed, 252 insertions(+), 3 deletions(-)
-
-diff --git a/src/map-file b/src/map-file
-index d51596c..20e577a 100644
---- a/src/map-file
-+++ b/src/map-file
-@@ -94,12 +94,15 @@ pa_context_set_event_callback;
- pa_context_set_name;
- pa_context_set_sink_input_mute;
- pa_context_set_sink_input_volume;
-+pa_context_set_sink_input_volume_ramp;
- pa_context_set_sink_mute_by_index;
- pa_context_set_sink_mute_by_name;
- pa_context_set_sink_port_by_index;
- pa_context_set_sink_port_by_name;
- pa_context_set_sink_volume_by_index;
- pa_context_set_sink_volume_by_name;
-+pa_context_set_sink_volume_ramp_by_index;
-+pa_context_set_sink_volume_ramp_by_name;
- pa_context_set_source_output_mute;
- pa_context_set_source_output_volume;
- pa_context_set_source_mute_by_index;
-diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
-index 2d54fdb..a72020a 100644
---- a/src/pulse/introspect.c
-+++ b/src/pulse/introspect.c
-@@ -1446,6 +1446,56 @@ pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name
-     return o;
- }
-+pa_operation* pa_context_set_sink_volume_ramp_by_index(pa_context *c, uint32_t idx, const pa_cvolume_ramp *ramp, pa_context_success_cb_t cb, void *userdata) {
-+    pa_operation *o;
-+    pa_tagstruct *t;
-+    uint32_t tag;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+    pa_assert(ramp);
-+
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+
-+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+    t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME_RAMP, &tag);
-+    pa_tagstruct_putu32(t, idx);
-+    pa_tagstruct_puts(t, NULL);
-+    pa_tagstruct_put_cvolume_ramp(t, ramp);
-+    pa_pstream_send_tagstruct(c->pstream, t);
-+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+    return o;
-+}
-+
-+pa_operation* pa_context_set_sink_volume_ramp_by_name(pa_context *c, const char *name, const pa_cvolume_ramp *ramp, pa_context_success_cb_t cb, void *userdata) {
-+    pa_operation *o;
-+    pa_tagstruct *t;
-+    uint32_t tag;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+    pa_assert(name);
-+    pa_assert(ramp);
-+
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID);
-+
-+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+    t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME_RAMP, &tag);
-+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
-+    pa_tagstruct_puts(t, name);
-+    pa_tagstruct_put_cvolume_ramp(t, ramp);
-+    pa_pstream_send_tagstruct(c->pstream, t);
-+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+    return o;
-+}
-+
- pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) {
-     pa_operation *o;
-     pa_tagstruct *t;
-@@ -1543,6 +1593,30 @@ pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mu
-     return o;
- }
-+pa_operation* pa_context_set_sink_input_volume_ramp(pa_context *c, uint32_t idx, const pa_cvolume_ramp *ramp, pa_context_success_cb_t cb, void *userdata) {
-+    pa_operation *o;
-+    pa_tagstruct *t;
-+    uint32_t tag;
-+
-+    pa_assert(c);
-+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
-+    pa_assert(ramp);
-+
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
-+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
-+
-+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-+
-+    t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP, &tag);
-+    pa_tagstruct_putu32(t, idx);
-+    pa_tagstruct_puts(t, NULL);
-+    pa_tagstruct_put_cvolume_ramp(t, ramp);
-+    pa_pstream_send_tagstruct(c->pstream, t);
-+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-+
-+    return o;
-+}
-+
- pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) {
-     pa_operation *o;
-     pa_tagstruct *t;
-diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
-index 22fefed..127cade 100644
---- a/src/pulse/introspect.h
-+++ b/src/pulse/introspect.h
-@@ -287,6 +287,12 @@ pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int
- /** Set the mute switch of a sink device specified by its name */
- pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata);
-+/** Set the volume ramp of a sink device specified by its index */
-+pa_operation* pa_context_set_sink_volume_ramp_by_index(pa_context *c, uint32_t idx, const pa_cvolume_ramp *ramp, pa_context_success_cb_t cb, void *userdata);
-+
-+/** Set the volume ramp of a sink device specified by its name */
-+pa_operation* pa_context_set_sink_volume_ramp_by_name(pa_context *c, const char *name, const pa_cvolume_ramp *ramp, pa_context_success_cb_t cb, void *userdata);
-+
- /** Suspend/Resume a sink. \since 0.9.7 */
- pa_operation* pa_context_suspend_sink_by_name(pa_context *c, const char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata);
-@@ -604,6 +610,9 @@ pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mu
- /** Kill a sink input. */
- pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata);
-+/** Set the volume ramp of a sink input specified by its index */
-+pa_operation* pa_context_set_sink_input_volume_ramp(pa_context *c, uint32_t idx, const pa_cvolume_ramp *ramp, pa_context_success_cb_t cb, void *userdata);
-+
- /** @} */
- /** @{ \name Source Outputs */
-diff --git a/src/pulse/stream.c b/src/pulse/stream.c
-index 8e35c29..501b5b6 100644
---- a/src/pulse/stream.c
-+++ b/src/pulse/stream.c
-@@ -1213,7 +1213,8 @@ static int create_stream(
-                                               PA_STREAM_START_UNMUTED|
-                                               PA_STREAM_FAIL_ON_SUSPEND|
-                                               PA_STREAM_RELATIVE_VOLUME|
--                                              PA_STREAM_PASSTHROUGH)), PA_ERR_INVALID);
-+                                              PA_STREAM_PASSTHROUGH|
-+                                              PA_STREAM_START_RAMP_MUTED)), PA_ERR_INVALID);
-     PA_CHECK_VALIDITY(s->context, s->context->version >= 12 || !(flags & PA_STREAM_VARIABLE_RATE), PA_ERR_NOTSUPPORTED);
-     PA_CHECK_VALIDITY(s->context, s->context->version >= 13 || !(flags & PA_STREAM_PEAK_DETECT), PA_ERR_NOTSUPPORTED);
-@@ -1372,6 +1373,9 @@ static int create_stream(
-         pa_tagstruct_put_boolean(t, flags & (PA_STREAM_PASSTHROUGH));
-     }
-+    if (s->context->version >= 22 && s->direction == PA_STREAM_PLAYBACK)
-+        pa_tagstruct_put_boolean(t, flags & (PA_STREAM_START_RAMP_MUTED));
-+
-     pa_pstream_send_tagstruct(s->context->pstream, t);
-     pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL);
-diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h
-index dad82e0..301e2e7 100644
---- a/src/pulsecore/native-common.h
-+++ b/src/pulsecore/native-common.h
-@@ -176,6 +176,9 @@ enum {
-     /* Supported since protocol v27 (3.0) */
-     PA_COMMAND_SET_PORT_LATENCY_OFFSET,
-+    PA_COMMAND_SET_SINK_VOLUME_RAMP,
-+    PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP,
-+
-     PA_COMMAND_MAX
- };
-diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c
-index 4033240..8643378 100644
---- a/src/pulsecore/pdispatch.c
-+++ b/src/pulsecore/pdispatch.c
-@@ -190,6 +190,8 @@ static const char *command_names[PA_COMMAND_MAX] = {
-     [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = "SET_SOURCE_OUTPUT_VOLUME",
-     [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = "SET_SOURCE_OUTPUT_MUTE",
-+    [PA_COMMAND_SET_SINK_VOLUME_RAMP] = "SET_SINK_VOLUME_RAMP",
-+    [PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP] = "SET_SINK_INPUT_VOLUME_RAMP",
- };
- #endif
-diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
-index 41b4b50..4304cd4 100644
---- a/src/pulsecore/protocol-native.c
-+++ b/src/pulsecore/protocol-native.c
-@@ -294,6 +294,7 @@ static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag,
- static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
- static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
- static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
-+static void command_set_volume_ramp(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
- static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
-     [PA_COMMAND_ERROR] = NULL,
-@@ -397,6 +398,9 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
-     [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = command_set_port_latency_offset,
-+    [PA_COMMAND_SET_SINK_VOLUME_RAMP] = command_set_volume_ramp,
-+    [PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP] = command_set_volume_ramp,
-+
-     [PA_COMMAND_EXTENSION] = command_extension
- };
-@@ -1994,7 +1998,8 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
-         muted_set = false,
-         fail_on_suspend = false,
-         relative_volume = false,
--        passthrough = false;
-+        passthrough = false,
-+        ramp_muted = false;
-     pa_sink_input_flags_t flags = 0;
-     pa_proplist *p = NULL;
-@@ -2122,6 +2127,7 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
-             }
-             pa_idxset_put(formats, format, NULL);
-         }
-+
-     }
-     if (n_formats == 0) {
-@@ -2134,6 +2140,11 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
-         }
-     }
-+    if (pa_tagstruct_get_boolean(t, &ramp_muted) < 0 ) {
-+        protocol_error(c);
-+        goto finish;
-+    }
-+
-     if (!pa_tagstruct_eof(t)) {
-         protocol_error(c);
-         goto finish;
-@@ -2165,7 +2176,8 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
-         (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
-         (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
-         (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
--        (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0);
-+        (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0) |
-+        (ramp_muted ? PA_SINK_INPUT_START_RAMP_MUTED : 0);
-     /* Only since protocol version 15 there's a separate muted_set
-      * flag. For older versions we synthesize it here */
-@@ -3797,6 +3809,71 @@ static void command_set_volume(
-     pa_pstream_send_simple_ack(c->pstream, tag);
- }
-+static void command_set_volume_ramp(
-+        pa_pdispatch *pd,
-+        uint32_t command,
-+        uint32_t tag,
-+        pa_tagstruct *t,
-+        void *userdata) {
-+
-+    pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
-+    uint32_t idx;
-+    pa_cvolume_ramp ramp;
-+    pa_sink *sink = NULL;
-+    pa_sink_input *si = NULL;
-+    const char *name = NULL;
-+    const char *client_name;
-+
-+    pa_native_connection_assert_ref(c);
-+    pa_assert(t);
-+
-+    if (pa_tagstruct_getu32(t, &idx) < 0 ||
-+        (command == PA_COMMAND_SET_SINK_VOLUME_RAMP && pa_tagstruct_gets(t, &name) < 0) ||
-+        (command == PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP && pa_tagstruct_gets(t, &name) < 0) ||
-+        pa_tagstruct_get_cvolume_ramp(t, &ramp) ||
-+        !pa_tagstruct_eof(t)) {
-+        protocol_error(c);
-+        return;
-+    }
-+
-+    CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
-+    CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_VOLUME ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
-+    CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
-+    CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
-+    CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
-+
-+    switch (command) {
-+
-+        case PA_COMMAND_SET_SINK_VOLUME_RAMP:
-+            if (idx != PA_INVALID_INDEX)
-+                sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
-+            else
-+                sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
-+            break;
-+
-+        case PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP:
-+            si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
-+            break;
-+
-+        default:
-+            pa_assert_not_reached();
-+    }
-+
-+    CHECK_VALIDITY(c->pstream, sink || si, tag, PA_ERR_NOENTITY);
-+
-+    client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
-+
-+    if (sink) {
-+        pa_log_debug("Client %s changes volume ramp of sink %s.", client_name, sink->name);
-+        pa_sink_set_volume_ramp(sink, &ramp, TRUE, TRUE);
-+    } else if (si) {
-+        pa_log_debug("Client %s changes volume ramp of sink input %s.", client_name, pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
-+        pa_sink_input_set_volume_ramp(si, &ramp, TRUE, TRUE);
-+    }
-+
-+    pa_pstream_send_simple_ack(c->pstream, tag);
-+}
-+
- static void command_set_mute(
-         pa_pdispatch *pd,
-         uint32_t command,
-diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c
-index e51fcf2..aba0178 100644
---- a/src/pulsecore/tagstruct.c
-+++ b/src/pulsecore/tagstruct.c
-@@ -256,6 +256,35 @@ void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) {
-     }
- }
-+void pa_tagstruct_put_cvolume_ramp(pa_tagstruct *t, const pa_cvolume_ramp *ramp) {
-+    unsigned i;
-+    pa_volume_ramp_type_t type;
-+    long length;
-+    pa_volume_t target;
-+
-+    pa_assert(t);
-+    pa_assert(ramp);
-+    extend(t, 2 + ramp->channels * (sizeof(pa_volume_ramp_type_t) + sizeof(long) + sizeof(pa_volume_t)));
-+
-+    t->data[t->length++] = PA_TAG_CVOLUME_RAMP;
-+    t->data[t->length++] = ramp->channels;
-+
-+    for (i = 0; i < ramp->channels; i++) {
-+        type = htonl(ramp->ramps[i].type);
-+        target = htonl(ramp->ramps[i].target);
-+        length = htonl(ramp->ramps[i].length);
-+
-+        memcpy(t->data + t->length, &type, sizeof(pa_volume_ramp_type_t));
-+        t->length += sizeof(pa_volume_ramp_type_t);
-+
-+        memcpy(t->data + t->length, &length, sizeof(long));
-+        t->length += sizeof(long);
-+
-+        memcpy(t->data + t->length, &target, sizeof(pa_volume_t));
-+        t->length += sizeof(pa_volume_t);
-+    }
-+}
-+
- void pa_tagstruct_put_volume(pa_tagstruct *t, pa_volume_t vol) {
-     uint32_t u;
-     pa_assert(t);
-@@ -579,6 +608,51 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
-     return 0;
- }
-+int pa_tagstruct_get_cvolume_ramp(pa_tagstruct *t, pa_cvolume_ramp *ramp) {
-+    unsigned i;
-+    pa_volume_ramp_type_t type;
-+    long length;
-+    pa_volume_t target;
-+    uint8_t *read_ptr;
-+
-+    pa_assert(t);
-+    pa_assert(ramp);
-+
-+    if (t->rindex+2 > t->length)
-+        return -1;
-+
-+    if (t->data[t->rindex] != PA_TAG_CVOLUME_RAMP)
-+        return -1;
-+
-+    if ((ramp->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
-+        return -1;
-+
-+    if (t->rindex+2+ramp->channels*(sizeof(pa_volume_ramp_type_t)+sizeof(long)+sizeof(pa_volume_t)) > t->length)
-+        return -1;
-+
-+    read_ptr = t->data + t->rindex + 2;
-+
-+    for (i = 0; i < ramp->channels; i++) {
-+        memcpy(&type, read_ptr, sizeof(pa_volume_ramp_type_t));
-+        ramp->ramps[i].type = (pa_volume_ramp_type_t) ntohl(type);
-+        read_ptr += sizeof(pa_volume_ramp_type_t);
-+
-+
-+        memcpy(&length, read_ptr, sizeof(long));
-+        ramp->ramps[i].length = (long) ntohl(length);
-+        read_ptr += sizeof(long);
-+
-+
-+        memcpy(&target, read_ptr, sizeof(pa_volume_t));
-+        ramp->ramps[i].target = (pa_volume_t) ntohl(target);
-+        read_ptr += sizeof(pa_volume_t);
-+    }
-+
-+    t->rindex = read_ptr - t->data;
-+
-+    return 0;
-+}
-+
- int pa_tagstruct_get_volume(pa_tagstruct*t, pa_volume_t *vol) {
-     uint32_t u;
-diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h
-index 9fef255..4634bd6 100644
---- a/src/pulsecore/tagstruct.h
-+++ b/src/pulsecore/tagstruct.h
-@@ -60,6 +60,7 @@ enum {
-     PA_TAG_PROPLIST = 'P',
-     PA_TAG_VOLUME = 'V',
-     PA_TAG_FORMAT_INFO = 'f',
-+    PA_TAG_CVOLUME_RAMP = 'J'
- };
- pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length);
-@@ -86,6 +87,7 @@ void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume);
- void pa_tagstruct_put_proplist(pa_tagstruct *t, pa_proplist *p);
- void pa_tagstruct_put_volume(pa_tagstruct *t, pa_volume_t volume);
- void pa_tagstruct_put_format_info(pa_tagstruct *t, pa_format_info *f);
-+void pa_tagstruct_put_cvolume_ramp(pa_tagstruct *t, const pa_cvolume_ramp *ramp);
- int pa_tagstruct_get(pa_tagstruct *t, ...);
-@@ -104,5 +106,6 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *v);
- int pa_tagstruct_get_proplist(pa_tagstruct *t, pa_proplist *p);
- int pa_tagstruct_get_volume(pa_tagstruct *t, pa_volume_t *v);
- int pa_tagstruct_get_format_info(pa_tagstruct *t, pa_format_info *f);
-+int pa_tagstruct_get_cvolume_ramp(pa_tagstruct *t, pa_cvolume_ramp *ramp);
- #endif
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0047-adjust-default-bluetooth-profile-to-off.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0047-adjust-default-bluetooth-profile-to-off.patch
deleted file mode 100644 (file)
index 4f20de2..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Wed, 14 Aug 2013 15:00:52 +0300
-Subject: adjust default bluetooth profile to off
-
-Change-Id: I95ca525b0d20c1a864a0c66060767bb4c2160400
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/bluetooth/module-bluez4-device.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/src/modules/bluetooth/module-bluez4-device.c b/src/modules/bluetooth/module-bluez4-device.c
-index eba92c6..6b775b7 100644
---- a/src/modules/bluetooth/module-bluez4-device.c
-+++ b/src/modules/bluetooth/module-bluez4-device.c
-@@ -2527,6 +2527,8 @@ static int add_card(struct userdata *u) {
-         else
-             pa_log_warn("Profile '%s' not valid or not supported by device.", default_profile);
-     }
-+    else
-+      pa_card_new_data_set_profile(&data, p->name);
-     u->card = pa_card_new(u->core, &data);
-     pa_card_new_data_done(&data);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0048-Add-bt_profile_set-patch-which-fixed-bt-a2dp-hsp-pro.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0048-Add-bt_profile_set-patch-which-fixed-bt-a2dp-hsp-pro.patch
deleted file mode 100644 (file)
index 83227f7..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-From: "vivian,zhang" <vivian.zhang@intel.com>
-Date: Wed, 17 Jul 2013 11:17:40 +0800
-Subject: Add bt_profile_set patch which fixed bt a2dp&hsp profile setting
- issues in mobile
-
-Change-Id: I9bc3649b02ab7ac56584211789a3ea18ff17fbb7
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- configure.ac                                   | 13 +++++++++++++
- src/Makefile.am                                |  3 +++
- src/modules/bluetooth/module-bluez4-discover.c | 18 ++++++++++++++++++
- 3 files changed, 34 insertions(+)
-
-diff --git a/configure.ac b/configure.ac
-index 870375f..6a6bc83 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -679,6 +679,19 @@ fi
- AM_CONDITIONAL(USE_DLOG, test "x$USE_DLOG" = "xyes")
- dnl end --------------------------------------------------------------------
-+dnl use bt-profile-set --------------------------------------------------------------------------
-+AC_ARG_ENABLE(bt-profile-set, AC_HELP_STRING([--enable-bt-profile-set], [enable bt profile param]),
-+[
-+ case "${enableval}" in
-+        yes) USE_BT_PROFILE_SET=yes ;;
-+        no)  USE_BT_PROFILE_SET=no ;;
-+        *)   AC_MSG_ERROR(bad value ${enableval} for --enable-bt-profile-set) ;;
-+ esac
-+ ],[USE_BT_PROFILE_SET=no])
-+
-+AM_CONDITIONAL(USE_BT_PROFILE_SET, test "x$USE_BT_PROFILE_SET" = "xyes")
-+dnl end --------------------------------------------------------------------
-+
- #### atomic-ops ####
- AC_MSG_CHECKING([whether we need libatomic_ops])
-diff --git a/src/Makefile.am b/src/Makefile.am
-index a60b5bf..b09903f 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -2082,6 +2082,9 @@ module_bluetooth_discover_la_CFLAGS = $(AM_CFLAGS)
- if HAVE_BT_A2DP_APTX
- module_bluetooth_discover_la_CFLAGS += -DBLUETOOTH_APTX_SUPPORT
- endif
-+if USE_BT_PROFILE_SET
-+module_bluetooth_discover_la_CFLAGS += -DBLUETOOTH_PROFILE_SET
-+endif
- # Bluetooth BlueZ 4 sink / source
- module_bluez4_discover_la_SOURCES = modules/bluetooth/module-bluez4-discover.c
-diff --git a/src/modules/bluetooth/module-bluez4-discover.c b/src/modules/bluetooth/module-bluez4-discover.c
-index 7673ba7..aaaa095 100644
---- a/src/modules/bluetooth/module-bluez4-discover.c
-+++ b/src/modules/bluetooth/module-bluez4-discover.c
-@@ -79,9 +79,27 @@ static pa_hook_result_t load_module_for_device(pa_bluez4_discovery *y, const pa_
-             pa_module *m = NULL;
-             char *args;
-+#ifdef BLUETOOTH_PROFILE_SET
-+            const char *profile = NULL;
-+
-+            if ((d->transports[PROFILE_A2DP] && d->transports[PROFILE_A2DP]->state != PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)) {
-+                profile = "a2dp";
-+            } if ((d->transports[PROFILE_A2DP_SOURCE] && d->transports[PROFILE_A2DP_SOURCE]->state != PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)) {
-+                profile = "a2dp_source";
-+            } else if ((d->transports[PROFILE_HFGW] && d->transports[PROFILE_HFGW]->state != PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)) {
-+                profile = "hfgw";
-+            }
-+            if (!profile)
-+                return PA_HOOK_OK;
-+#endif
-+
-             /* Oh, awesome, a new device has shown up and been connected! */
-+#ifdef BLUETOOTH_PROFILE_SET
-+            args = pa_sprintf_malloc("address=\"%s\" path=\"%s\" profile=\"%s\"", d->address, d->path, profile);
-+#else
-             args = pa_sprintf_malloc("address=\"%s\" path=\"%s\"", d->address, d->path);
-+#endif
-             if (pa_modargs_get_value(u->modargs, "sco_sink", NULL) &&
-                 pa_modargs_get_value(u->modargs, "sco_source", NULL)) {
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0049-added-pulseaudio.service-file.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0049-added-pulseaudio.service-file.patch
deleted file mode 100644 (file)
index c4c125c..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Tue, 11 Jun 2013 17:03:27 +0300
-Subject: added pulseaudio.service file
-
-Change-Id: I8efef41060189f116be49b3455c588d67f045f82
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- pulseaudio.service | 10 ++++++++++
- 1 file changed, 10 insertions(+)
- create mode 100644 pulseaudio.service
-
-diff --git a/pulseaudio.service b/pulseaudio.service
-new file mode 100644
-index 0000000..f9d8592
---- /dev/null
-+++ b/pulseaudio.service
-@@ -0,0 +1,10 @@
-+[Unit]
-+Description=pulseaudio service
-+After=syslog.target dbus.service
-+
-+[Service]
-+Type=simple
-+ExecStart=/usr/bin/pulseaudio --system
-+
-+[Install]
-+WantedBy=multi-user.target
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0050-.gitignore-Add-pulsecore-config.h.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0050-.gitignore-Add-pulsecore-config.h.patch
deleted file mode 100644 (file)
index c5c1d3b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 24 Feb 2014 12:38:31 +0200
-Subject: .gitignore: Add pulsecore-config.h
-
-Change-Id: I8409f1964e65e79669eaeb4930c6d536417a0b05
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- .gitignore | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/.gitignore b/.gitignore
-index f41ee72..b4a465e 100644
---- a/.gitignore
-+++ b/.gitignore
-@@ -34,3 +34,4 @@ missing
- mkinstalldirs
- stamp-*
- .dirstamp
-+pulsecore-config.h
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0051-pactl-Fix-crash-with-older-servers.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0051-pactl-Fix-crash-with-older-servers.patch
deleted file mode 100644 (file)
index cd4736c..0000000
+++ /dev/null
@@ -1,405 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Sun, 16 Feb 2014 14:30:38 +0200
-Subject: pactl: Fix crash with older servers
-
-Servers older than 0.9.15 don't know anything about cards, and card
-operations will return a NULL pa_operation object when connected to
-that old server. We must check the pa_operation pointer before passing
-it to pa_operation_unref(), otherwise a NULL operation will result in
-a crash.
-
-Change-Id: Idc258479c077aafaff6254b76acb18034a158107
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/utils/pactl.c | 203 +++++++++++++++++++++++++++++++++++-------------------
- 1 file changed, 133 insertions(+), 70 deletions(-)
-
-diff --git a/src/utils/pactl.c b/src/utils/pactl.c
-index 1d8faa4..958d700 100644
---- a/src/utils/pactl.c
-+++ b/src/utils/pactl.c
-@@ -94,7 +94,7 @@ static pa_stream *sample_stream = NULL;
- static pa_sample_spec sample_spec;
- static pa_channel_map channel_map;
- static size_t sample_length = 0;
--static int actions = 1;
-+static int actions = 0;
- static bool nl = false;
-@@ -1046,6 +1046,7 @@ static void set_sink_formats(pa_context *c, uint32_t sink, const char *str) {
-     char *format = NULL;
-     const char *state = NULL;
-     int i = 0;
-+    pa_operation *o = NULL;
-     while ((format = pa_split(str, ";", &state))) {
-         pa_format_info *f = pa_format_info_from_string(pa_strip(format));
-@@ -1059,7 +1060,11 @@ static void set_sink_formats(pa_context *c, uint32_t sink, const char *str) {
-         pa_xfree(format);
-     }
--    pa_operation_unref(pa_ext_device_restore_save_formats(c, PA_DEVICE_TYPE_SINK, sink, i, f_arr, simple_callback, NULL));
-+    o = pa_ext_device_restore_save_formats(c, PA_DEVICE_TYPE_SINK, sink, i, f_arr, simple_callback, NULL);
-+    if (o) {
-+        pa_operation_unref(o);
-+        actions++;
-+    }
- done:
-     if (format)
-@@ -1185,7 +1190,10 @@ static void context_subscribe_callback(pa_context *c, pa_subscription_event_type
- }
- static void context_state_callback(pa_context *c, void *userdata) {
-+    pa_operation *o = NULL;
-+
-     pa_assert(c);
-+
-     switch (pa_context_get_state(c)) {
-         case PA_CONTEXT_CONNECTING:
-         case PA_CONTEXT_AUTHORIZING:
-@@ -1195,21 +1203,26 @@ static void context_state_callback(pa_context *c, void *userdata) {
-         case PA_CONTEXT_READY:
-             switch (action) {
-                 case STAT:
--                    pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
-+                    o = pa_context_stat(c, stat_callback, NULL);
-                     if (short_list_format)
-                         break;
--                    actions++;
-+
-+                    if (o) {
-+                        pa_operation_unref(o);
-+                        actions++;
-+                    }
-+                    /* Fall through */
-                 case INFO:
--                    pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
-+                    o = pa_context_get_server_info(c, get_server_info_callback, NULL);
-                     break;
-                 case PLAY_SAMPLE:
--                    pa_operation_unref(pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL));
-+                    o = pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL);
-                     break;
-                 case REMOVE_SAMPLE:
--                    pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL));
-+                    o = pa_context_remove_sample(c, sample_name, simple_callback, NULL);
-                     break;
-                 case UPLOAD_SAMPLE:
-@@ -1219,165 +1232,205 @@ static void context_state_callback(pa_context *c, void *userdata) {
-                     pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
-                     pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
-                     pa_stream_connect_upload(sample_stream, sample_length);
-+                    actions++;
-                     break;
-                 case EXIT:
--                    pa_operation_unref(pa_context_exit_daemon(c, simple_callback, NULL));
-+                    o = pa_context_exit_daemon(c, simple_callback, NULL);
-                     break;
-                 case LIST:
-                     if (list_type) {
-                         if (pa_streq(list_type, "modules"))
--                            pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
-+                            o = pa_context_get_module_info_list(c, get_module_info_callback, NULL);
-                         else if (pa_streq(list_type, "sinks"))
--                            pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
-+                            o = pa_context_get_sink_info_list(c, get_sink_info_callback, NULL);
-                         else if (pa_streq(list_type, "sources"))
--                            pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
-+                            o = pa_context_get_source_info_list(c, get_source_info_callback, NULL);
-                         else if (pa_streq(list_type, "sink-inputs"))
--                            pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
-+                            o = pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL);
-                         else if (pa_streq(list_type, "source-outputs"))
--                            pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
-+                            o = pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL);
-                         else if (pa_streq(list_type, "clients"))
--                            pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
-+                            o = pa_context_get_client_info_list(c, get_client_info_callback, NULL);
-                         else if (pa_streq(list_type, "samples"))
--                            pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
-+                            o = pa_context_get_sample_info_list(c, get_sample_info_callback, NULL);
-                         else if (pa_streq(list_type, "cards"))
--                            pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
-+                            o = pa_context_get_card_info_list(c, get_card_info_callback, NULL);
-                       else if (pa_streq(list_type, "nodes"))
--                          pa_operation_unref(pa_ext_node_manager_read_nodes(c, node_list_callback, NULL));
-+                          o = pa_ext_node_manager_read_nodes(c, node_list_callback, NULL);
-                         else
-                             pa_assert_not_reached();
-                     } else {
--                        actions = 8;
--                        pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
--                        pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
--                        pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
--                        pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
--                        pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
--                        pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
--                        pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
--                        pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
-+                        o = pa_context_get_module_info_list(c, get_module_info_callback, NULL);
-+                        if (o) {
-+                            pa_operation_unref(o);
-+                            actions++;
-+                        }
-+
-+                        o = pa_context_get_sink_info_list(c, get_sink_info_callback, NULL);
-+                        if (o) {
-+                            pa_operation_unref(o);
-+                            actions++;
-+                        }
-+
-+                        o = pa_context_get_source_info_list(c, get_source_info_callback, NULL);
-+                        if (o) {
-+                            pa_operation_unref(o);
-+                            actions++;
-+                        }
-+                        o = pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL);
-+                        if (o) {
-+                            pa_operation_unref(o);
-+                            actions++;
-+                        }
-+
-+                        o = pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL);
-+                        if (o) {
-+                            pa_operation_unref(o);
-+                            actions++;
-+                        }
-+
-+                        o = pa_context_get_client_info_list(c, get_client_info_callback, NULL);
-+                        if (o) {
-+                            pa_operation_unref(o);
-+                            actions++;
-+                        }
-+
-+                        o = pa_context_get_sample_info_list(c, get_sample_info_callback, NULL);
-+                        if (o) {
-+                            pa_operation_unref(o);
-+                            actions++;
-+                        }
-+
-+                        o = pa_context_get_card_info_list(c, get_card_info_callback, NULL);
-+                        if (o) {
-+                            pa_operation_unref(o);
-+                            actions++;
-+                        }
-+
-+                        o = NULL;
-                     }
-                     break;
-                 case MOVE_SINK_INPUT:
--                    pa_operation_unref(pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL));
-+                    o = pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL);
-                     break;
-                 case MOVE_SOURCE_OUTPUT:
--                    pa_operation_unref(pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL));
-+                    o = pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL);
-                     break;
-                 case LOAD_MODULE:
--                    pa_operation_unref(pa_context_load_module(c, module_name, module_args, index_callback, NULL));
-+                    o = pa_context_load_module(c, module_name, module_args, index_callback, NULL);
-                     break;
-                 case UNLOAD_MODULE:
-                     if (module_name)
--                        pa_operation_unref(pa_context_get_module_info_list(c, unload_module_by_name_callback, NULL));
-+                        o = pa_context_get_module_info_list(c, unload_module_by_name_callback, NULL);
-                     else
--                        pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL));
-+                        o = pa_context_unload_module(c, module_index, simple_callback, NULL);
-                     break;
-                 case SUSPEND_SINK:
-                     if (sink_name)
--                        pa_operation_unref(pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL));
-+                        o = pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL);
-                     else
--                        pa_operation_unref(pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
-+                        o = pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL);
-                     break;
-                 case SUSPEND_SOURCE:
-                     if (source_name)
--                        pa_operation_unref(pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL));
-+                        o = pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL);
-                     else
--                        pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
-+                        o = pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL);
-                     break;
-                 case SET_CARD_PROFILE:
--                    pa_operation_unref(pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL));
-+                    o = pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL);
-                     break;
-                 case SET_SINK_PORT:
--                    pa_operation_unref(pa_context_set_sink_port_by_name(c, sink_name, port_name, simple_callback, NULL));
-+                    o = pa_context_set_sink_port_by_name(c, sink_name, port_name, simple_callback, NULL);
-                     break;
-                 case SET_DEFAULT_SINK:
--                    pa_operation_unref(pa_context_set_default_sink(c, sink_name, simple_callback, NULL));
-+                    o = pa_context_set_default_sink(c, sink_name, simple_callback, NULL);
-                     break;
-                 case SET_SOURCE_PORT:
--                    pa_operation_unref(pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL));
-+                    o = pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL);
-                     break;
-                 case SET_DEFAULT_SOURCE:
--                    pa_operation_unref(pa_context_set_default_source(c, source_name, simple_callback, NULL));
-+                    o = pa_context_set_default_source(c, source_name, simple_callback, NULL);
-                     break;
-                 case SET_SINK_MUTE:
-                     if (mute == TOGGLE_MUTE)
--                        pa_operation_unref(pa_context_get_sink_info_by_name(c, sink_name, sink_toggle_mute_callback, NULL));
-+                        o = pa_context_get_sink_info_by_name(c, sink_name, sink_toggle_mute_callback, NULL);
-                     else
--                        pa_operation_unref(pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL));
-+                        o = pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL);
-                     break;
-                 case SET_SOURCE_MUTE:
-                     if (mute == TOGGLE_MUTE)
--                        pa_operation_unref(pa_context_get_source_info_by_name(c, source_name, source_toggle_mute_callback, NULL));
-+                        o = pa_context_get_source_info_by_name(c, source_name, source_toggle_mute_callback, NULL);
-                     else
--                        pa_operation_unref(pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL));
-+                        o = pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL);
-                     break;
-                 case SET_SINK_INPUT_MUTE:
-                     if (mute == TOGGLE_MUTE)
--                        pa_operation_unref(pa_context_get_sink_input_info(c, sink_input_idx, sink_input_toggle_mute_callback, NULL));
-+                        o = pa_context_get_sink_input_info(c, sink_input_idx, sink_input_toggle_mute_callback, NULL);
-                     else
--                        pa_operation_unref(pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL));
-+                        o = pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL);
-                     break;
-                 case SET_SOURCE_OUTPUT_MUTE:
-                     if (mute == TOGGLE_MUTE)
--                        pa_operation_unref(pa_context_get_source_output_info(c, source_output_idx, source_output_toggle_mute_callback, NULL));
-+                        o = pa_context_get_source_output_info(c, source_output_idx, source_output_toggle_mute_callback, NULL);
-                     else
--                        pa_operation_unref(pa_context_set_source_output_mute(c, source_output_idx, mute, simple_callback, NULL));
-+                        o = pa_context_set_source_output_mute(c, source_output_idx, mute, simple_callback, NULL);
-                     break;
-                 case SET_SINK_VOLUME:
-                     if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
--                        pa_operation_unref(pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL));
-+                        o = pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL);
-                     } else {
-                         pa_cvolume v;
-                         pa_cvolume_set(&v, 1, volume);
--                        pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL));
-+                        o = pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL);
-                     }
-                     break;
-                 case SET_SOURCE_VOLUME:
-                     if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
--                        pa_operation_unref(pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL));
-+                        o = pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL);
-                     } else {
-                         pa_cvolume v;
-                         pa_cvolume_set(&v, 1, volume);
--                        pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL));
-+                        o = pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL);
-                     }
-                     break;
-                 case SET_SINK_INPUT_VOLUME:
-                     if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
--                        pa_operation_unref(pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL));
-+                        o = pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL);
-                     } else {
-                         pa_cvolume v;
-                         pa_cvolume_set(&v, 1, volume);
--                        pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL));
-+                        o = pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL);
-                     }
-                     break;
-                 case SET_SOURCE_OUTPUT_VOLUME:
-                     if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
--                        pa_operation_unref(pa_context_get_source_output_info(c, source_output_idx, get_source_output_volume_callback, NULL));
-+                        o = pa_context_get_source_output_info(c, source_output_idx, get_source_output_volume_callback, NULL);
-                     } else {
-                         pa_cvolume v;
-                         pa_cvolume_set(&v, 1, volume);
--                        pa_operation_unref(pa_context_set_source_output_volume(c, source_output_idx, &v, simple_callback, NULL));
-+                        o = pa_context_set_source_output_volume(c, source_output_idx, &v, simple_callback, NULL);
-                     }
-                     break;
-@@ -1386,25 +1439,24 @@ static void context_state_callback(pa_context *c, void *userdata) {
-                     break;
-                 case SET_PORT_LATENCY_OFFSET:
--                    pa_operation_unref(pa_context_set_port_latency_offset(c, card_name, port_name, latency_offset, simple_callback, NULL));
-+                    o = pa_context_set_port_latency_offset(c, card_name, port_name, latency_offset, simple_callback, NULL);
-                     break;
-                 case SUBSCRIBE:
-                     pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
--                    pa_operation_unref(pa_context_subscribe(
--                                              c,
--                                              PA_SUBSCRIPTION_MASK_SINK|
--                                              PA_SUBSCRIPTION_MASK_SOURCE|
--                                              PA_SUBSCRIPTION_MASK_SINK_INPUT|
--                                              PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
--                                              PA_SUBSCRIPTION_MASK_MODULE|
--                                              PA_SUBSCRIPTION_MASK_CLIENT|
--                                              PA_SUBSCRIPTION_MASK_SAMPLE_CACHE|
--                                              PA_SUBSCRIPTION_MASK_SERVER|
--                                              PA_SUBSCRIPTION_MASK_CARD,
--                                              NULL,
--                                              NULL));
-+                    o = pa_context_subscribe(c,
-+                                             PA_SUBSCRIPTION_MASK_SINK|
-+                                             PA_SUBSCRIPTION_MASK_SOURCE|
-+                                             PA_SUBSCRIPTION_MASK_SINK_INPUT|
-+                                             PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
-+                                             PA_SUBSCRIPTION_MASK_MODULE|
-+                                             PA_SUBSCRIPTION_MASK_CLIENT|
-+                                             PA_SUBSCRIPTION_MASK_SAMPLE_CACHE|
-+                                             PA_SUBSCRIPTION_MASK_SERVER|
-+                                             PA_SUBSCRIPTION_MASK_CARD,
-+                                             NULL,
-+                                             NULL);
-                     break;
-               case NODE_CONNECT:
-                   pa_operation_unref(pa_ext_node_manager_connect_nodes(c,
-@@ -1422,6 +1474,17 @@ static void context_state_callback(pa_context *c, void *userdata) {
-                 default:
-                     pa_assert_not_reached();
-             }
-+
-+            if (o) {
-+                pa_operation_unref(o);
-+                actions++;
-+            }
-+
-+            if (actions == 0) {
-+                pa_log("Operation failed: %s", pa_strerror(pa_context_errno(c)));
-+                quit(1);
-+            }
-+
-             break;
-         case PA_CONTEXT_TERMINATED:
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0052-volume-Increase-PA_SW_VOLUME_SNPRINT_DB_MAX.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0052-volume-Increase-PA_SW_VOLUME_SNPRINT_DB_MAX.patch
deleted file mode 100644 (file)
index 32330d6..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Sun, 9 Mar 2014 10:50:23 +0200
-Subject: volume: Increase PA_SW_VOLUME_SNPRINT_DB_MAX
-
-10 bytes isn't enough for "-123.45 dB", including the terminating null
-byte.
-
-Change-Id: I865060befd01d3dde69556c1f90b7de55350501a
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulse/volume.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/pulse/volume.h b/src/pulse/volume.h
-index 3ffb573..cfdc85c 100644
---- a/src/pulse/volume.h
-+++ b/src/pulse/volume.h
-@@ -216,7 +216,7 @@ char *pa_volume_snprint(char *s, size_t l, pa_volume_t v);
-  * any release without warning and without being considered API or ABI
-  * breakage. You should not use this definition anywhere where it
-  * might become part of an ABI. \since 0.9.15 */
--#define PA_SW_VOLUME_SNPRINT_DB_MAX 10
-+#define PA_SW_VOLUME_SNPRINT_DB_MAX 11
- /** Pretty print a volume but show dB values. \since 0.9.15 */
- char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0053-sink-input-source-output-Fix-mute-saving.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0053-sink-input-source-output-Fix-mute-saving.patch
deleted file mode 100644 (file)
index fc389f6..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 14 Apr 2014 14:29:48 +0300
-Subject: sink-input, source-output: Fix mute saving
-
-Change-Id: I2298ab51a384c3ddfa33da3e941e03f5027b4d77
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/sink-input.c    | 2 +-
- src/pulsecore/source-output.c | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index dff6324..d0509b3 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -1470,7 +1470,7 @@ void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save) {
-     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
-     if (!i->muted == !mute) {
--        i->save_muted = i->save_muted || mute;
-+        i->save_muted |= save;
-         return;
-     }
-diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
-index 4e4b7e9..b12758a 100644
---- a/src/pulsecore/source-output.c
-+++ b/src/pulsecore/source-output.c
-@@ -1062,7 +1062,7 @@ void pa_source_output_set_mute(pa_source_output *o, bool mute, bool save) {
-     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
-     if (!o->muted == !mute) {
--        o->save_muted = o->save_muted || mute;
-+        o->save_muted |= save;
-         return;
-     }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0054-direction-Add-a-couple-of-direction-helper-functions.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0054-direction-Add-a-couple-of-direction-helper-functions.patch
deleted file mode 100644 (file)
index 3282596..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 26 Mar 2014 10:25:17 +0200
-Subject: direction: Add a couple of direction helper functions
-
-Change-Id: I365acd7ce3e7abcbcb8a532c79016fca558238e8
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- doxygen/doxygen.conf.in |  1 +
- src/Makefile.am         |  2 ++
- src/map-file            |  2 ++
- src/pulse/direction.c   | 46 ++++++++++++++++++++++++++++++++++++++++++++++
- src/pulse/direction.h   | 37 +++++++++++++++++++++++++++++++++++++
- src/pulse/pulseaudio.h  |  5 +++--
- 6 files changed, 91 insertions(+), 2 deletions(-)
- create mode 100644 src/pulse/direction.c
- create mode 100644 src/pulse/direction.h
-
-diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in
-index a078e27..40cea8b 100644
---- a/doxygen/doxygen.conf.in
-+++ b/doxygen/doxygen.conf.in
-@@ -421,6 +421,7 @@ INPUT = \
-     @srcdir@/../src/pulse/channelmap.h \
-     @srcdir@/../src/pulse/context.h \
-     @srcdir@/../src/pulse/def.h \
-+    @srcdir@/../src/pulse/direction.h \
-     @srcdir@/../src/pulse/error.h \
-     @srcdir@/../src/pulse/ext-stream-restore.h \
-     @srcdir@/../src/pulse/ext-device-manager.h \
-diff --git a/src/Makefile.am b/src/Makefile.am
-index b09903f..fe6cc53 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -758,6 +758,7 @@ pulseinclude_HEADERS = \
-               pulse/channelmap.h \
-               pulse/context.h \
-               pulse/def.h \
-+              pulse/direction.h \
-               pulse/error.h \
-               pulse/ext-device-manager.h \
-               pulse/ext-device-restore.h \
-@@ -810,6 +811,7 @@ libpulse_la_SOURCES = \
-               pulse/channelmap.c pulse/channelmap.h \
-               pulse/context.c pulse/context.h \
-               pulse/def.h \
-+              pulse/direction.c pulse/direction.h \
-               pulse/error.c pulse/error.h \
-               pulse/ext-device-manager.c pulse/ext-device-manager.h \
-               pulse/ext-device-restore.c pulse/ext-device-restore.h \
-diff --git a/src/map-file b/src/map-file
-index 20e577a..fbf3f22 100644
---- a/src/map-file
-+++ b/src/map-file
-@@ -153,6 +153,8 @@ pa_cvolume_set_position;
- pa_cvolume_snprint;
- pa_cvolume_snprint_verbose;
- pa_cvolume_valid;
-+pa_direction_to_string;
-+pa_direction_valid;
- pa_encoding_to_string;
- pa_ext_device_manager_delete;
- pa_ext_device_manager_enable_role_device_priority_routing;
-diff --git a/src/pulse/direction.c b/src/pulse/direction.c
-new file mode 100644
-index 0000000..95f5e00
---- /dev/null
-+++ b/src/pulse/direction.c
-@@ -0,0 +1,46 @@
-+/***
-+  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 "direction.h"
-+
-+#include <pulsecore/i18n.h>
-+
-+int pa_direction_valid(pa_direction_t direction) {
-+    if (direction != PA_DIRECTION_INPUT
-+            && direction != PA_DIRECTION_OUTPUT
-+            && direction != (PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT))
-+        return 0;
-+
-+    return 1;
-+}
-+
-+const char *pa_direction_to_string(pa_direction_t direction) {
-+    pa_init_i18n();
-+
-+    if (direction == PA_DIRECTION_INPUT)
-+        return _("input");
-+    if (direction == PA_DIRECTION_OUTPUT)
-+        return _("output");
-+    if (direction == (PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT))
-+        return _("bidirectional");
-+
-+    return _("invalid");
-+}
-diff --git a/src/pulse/direction.h b/src/pulse/direction.h
-new file mode 100644
-index 0000000..127f07a
---- /dev/null
-+++ b/src/pulse/direction.h
-@@ -0,0 +1,37 @@
-+#ifndef foodirectionhfoo
-+#define foodirectionhfoo
-+
-+/***
-+  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/def.h>
-+
-+/** \file
-+ * Utility functions for \ref pa_direction_t. */
-+
-+/** Return non-zero if the given value is a valid direction (either input,
-+ * output or bidirectional). \since 6.0 */
-+int pa_direction_valid(pa_direction_t direction) PA_GCC_CONST;
-+
-+/** Return a textual representation of the direction. \since 6.0 */
-+const char *pa_direction_to_string(pa_direction_t direction);
-+
-+#endif
-diff --git a/src/pulse/pulseaudio.h b/src/pulse/pulseaudio.h
-index 21b7213..2e270dd 100644
---- a/src/pulse/pulseaudio.h
-+++ b/src/pulse/pulseaudio.h
-@@ -23,6 +23,7 @@
-   USA.
- ***/
-+#include <pulse/direction.h>
- #include <pulse/mainloop-api.h>
- #include <pulse/sample.h>
- #include <pulse/format.h>
-@@ -49,8 +50,8 @@
- /** \file
-  * Include all libpulse header files at once. The following files are
-- * included: \ref mainloop-api.h, \ref sample.h, \ref def.h, \ref
-- * context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, \ref
-+ * included: \ref direction.h, \ref mainloop-api.h, \ref sample.h, \ref def.h,
-+ * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, \ref
-  * scache.h, \ref version.h, \ref error.h, \ref channelmap.h, \ref
-  * operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref
-  * thread-mainloop.h, \ref mainloop.h, \ref util.h, \ref proplist.h,
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0055-core-util-Add-pa_join.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0055-core-util-Add-pa_join.patch
deleted file mode 100644 (file)
index d510f44..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 26 Mar 2014 13:15:12 +0200
-Subject: core-util: Add pa_join()
-
-Change-Id: I84ac0ee7a3097fce8ed9bad26b210fc97db9e9a7
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/core-util.c | 18 ++++++++++++++++++
- src/pulsecore/core-util.h |  1 +
- 2 files changed, 19 insertions(+)
-
-diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
-index 1256a1e..508b3d3 100644
---- a/src/pulsecore/core-util.c
-+++ b/src/pulsecore/core-util.c
-@@ -1120,6 +1120,24 @@ char *pa_split_spaces(const char *c, const char **state) {
-     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() */
-diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
-index e6cb261..aba1863 100644
---- a/src/pulsecore/core-util.h
-+++ b/src/pulsecore/core-util.h
-@@ -108,6 +108,7 @@ static inline const char *pa_strna(const char *x) {
- 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/recipes-multimedia/pulseaudio/pulseaudio_5.0/0056-dynarray-Add-pa_dynarray_get_raw_array.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0056-dynarray-Add-pa_dynarray_get_raw_array.patch
deleted file mode 100644 (file)
index cf2c694..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 26 Mar 2014 13:33:31 +0200
-Subject: dynarray: Add pa_dynarray_get_raw_array()
-
-Change-Id: I6e40c2a20586d13c99c9d98059e4dbb1d0e9e562
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/dynarray.c | 6 ++++++
- src/pulsecore/dynarray.h | 1 +
- 2 files changed, 7 insertions(+)
-
-diff --git a/src/pulsecore/dynarray.c b/src/pulsecore/dynarray.c
-index b207eca..b65fb62 100644
---- a/src/pulsecore/dynarray.c
-+++ b/src/pulsecore/dynarray.c
-@@ -93,3 +93,9 @@ unsigned pa_dynarray_size(pa_dynarray *array) {
-     return array->n_entries;
- }
-+
-+void * const *pa_dynarray_get_raw_array(pa_dynarray *array) {
-+    pa_assert(array);
-+
-+    return array->data;
-+}
-diff --git a/src/pulsecore/dynarray.h b/src/pulsecore/dynarray.h
-index 04dd2d2..078acec 100644
---- a/src/pulsecore/dynarray.h
-+++ b/src/pulsecore/dynarray.h
-@@ -54,5 +54,6 @@ void *pa_dynarray_get(pa_dynarray *array, unsigned i);
- 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/recipes-multimedia/pulseaudio/pulseaudio_5.0/0057-dynarray-Add-PA_DYNARRAY_FOREACH.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0057-dynarray-Add-PA_DYNARRAY_FOREACH.patch
deleted file mode 100644 (file)
index 64d8ce5..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Thu, 19 Dec 2013 21:29:50 +0200
-Subject: dynarray: Add PA_DYNARRAY_FOREACH
-
-The PA_DYNARRAY_FOREACH macro requires that pa_dynarray_get() returns
-NULL if the index is out of bounds.
-
-Change-Id: If9db312516fbb079e8b67d94d35a44783ab3395a
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/dynarray.c  | 4 +++-
- src/pulsecore/dynarray.h  | 5 +++++
- src/pulsecore/tokenizer.c | 3 ---
- 3 files changed, 8 insertions(+), 4 deletions(-)
-
-diff --git a/src/pulsecore/dynarray.c b/src/pulsecore/dynarray.c
-index b65fb62..8dd8fab 100644
---- a/src/pulsecore/dynarray.c
-+++ b/src/pulsecore/dynarray.c
-@@ -74,7 +74,9 @@ void pa_dynarray_append(pa_dynarray *array, void *p) {
- void *pa_dynarray_get(pa_dynarray *array, unsigned i) {
-     pa_assert(array);
--    pa_assert(i < array->n_entries);
-+
-+    if (i >= array->n_entries)
-+        return NULL;
-     return array->data[i];
- }
-diff --git a/src/pulsecore/dynarray.h b/src/pulsecore/dynarray.h
-index 078acec..65030f2 100644
---- a/src/pulsecore/dynarray.h
-+++ b/src/pulsecore/dynarray.h
-@@ -48,6 +48,8 @@ pa_dynarray* pa_dynarray_new(pa_free_cb_t free_cb);
- void pa_dynarray_free(pa_dynarray *array);
- void pa_dynarray_append(pa_dynarray *array, void *p);
-+
-+/* Returns NULL if i is out of bounds. */
- void *pa_dynarray_get(pa_dynarray *array, unsigned i);
- /* Returns the removed item, or NULL if the array is empty. */
-@@ -56,4 +58,7 @@ 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);
-+#define PA_DYNARRAY_FOREACH(elem, array, idx) \
-+    for ((idx) = 0; ((elem) = pa_dynarray_get(array, idx)); (idx)++)
-+
- #endif
-diff --git a/src/pulsecore/tokenizer.c b/src/pulsecore/tokenizer.c
-index 4c610e8..d71a7da 100644
---- a/src/pulsecore/tokenizer.c
-+++ b/src/pulsecore/tokenizer.c
-@@ -80,8 +80,5 @@ const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i) {
-     pa_assert(a);
--    if (i >= pa_dynarray_size(a))
--        return NULL;
--
-     return pa_dynarray_get(a, i);
- }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0058-dynarray-Add-pa_dynarray_remove_last.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0058-dynarray-Add-pa_dynarray_remove_last.patch
deleted file mode 100644 (file)
index a6e0f56..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 21 May 2014 11:32:09 +0300
-Subject: dynarray: Add pa_dynarray_remove_last()
-
-Change-Id: I9098df96aac57a3ee2084061aa174f7ee02b1588
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/dynarray.c | 15 +++++++++++++++
- src/pulsecore/dynarray.h |  3 +++
- 2 files changed, 18 insertions(+)
-
-diff --git a/src/pulsecore/dynarray.c b/src/pulsecore/dynarray.c
-index 8dd8fab..c0b5fb0 100644
---- a/src/pulsecore/dynarray.c
-+++ b/src/pulsecore/dynarray.c
-@@ -81,6 +81,21 @@ void *pa_dynarray_get(pa_dynarray *array, unsigned i) {
-     return array->data[i];
- }
-+int pa_dynarray_remove_last(pa_dynarray *array) {
-+    void *entry;
-+
-+    pa_assert(array);
-+
-+    entry = pa_dynarray_steal_last(array);
-+    if (!entry)
-+        return -PA_ERR_NOENTITY;
-+
-+    if (array->free_cb)
-+        array->free_cb(entry);
-+
-+    return 0;
-+}
-+
- void *pa_dynarray_steal_last(pa_dynarray *array) {
-     pa_assert(array);
-diff --git a/src/pulsecore/dynarray.h b/src/pulsecore/dynarray.h
-index 65030f2..fd91433 100644
---- a/src/pulsecore/dynarray.h
-+++ b/src/pulsecore/dynarray.h
-@@ -52,6 +52,9 @@ void pa_dynarray_append(pa_dynarray *array, void *p);
- /* Returns NULL if i is out of bounds. */
- void *pa_dynarray_get(pa_dynarray *array, unsigned i);
-+/* Returns -PA_ERR_NOENTITY if the array is empty, and zero otherwise. */
-+int pa_dynarray_remove_last(pa_dynarray *array);
-+
- /* Returns the removed item, or NULL if the array is empty. */
- void *pa_dynarray_steal_last(pa_dynarray *array);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0059-dynarray-Add-pa_dynarray_remove_all.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0059-dynarray-Add-pa_dynarray_remove_all.patch
deleted file mode 100644 (file)
index d2e66b5..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 21 May 2014 11:36:19 +0300
-Subject: dynarray: Add pa_dynarray_remove_all()
-
-Change-Id: I35079f8fe4b361221a1bdc1fececbe318bf3ee0e
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/dynarray.c | 13 ++++++++-----
- src/pulsecore/dynarray.h |  2 ++
- 2 files changed, 10 insertions(+), 5 deletions(-)
-
-diff --git a/src/pulsecore/dynarray.c b/src/pulsecore/dynarray.c
-index c0b5fb0..6dba743 100644
---- a/src/pulsecore/dynarray.c
-+++ b/src/pulsecore/dynarray.c
-@@ -47,13 +47,9 @@ pa_dynarray* pa_dynarray_new(pa_free_cb_t free_cb) {
- }
- void pa_dynarray_free(pa_dynarray *array) {
--    unsigned i;
-     pa_assert(array);
--    if (array->free_cb)
--        for (i = 0; i < array->n_entries; i++)
--            array->free_cb(array->data[i]);
--
-+    pa_dynarray_remove_all(array);
-     pa_xfree(array->data);
-     pa_xfree(array);
- }
-@@ -105,6 +101,13 @@ void *pa_dynarray_steal_last(pa_dynarray *array) {
-         return NULL;
- }
-+void pa_dynarray_remove_all(pa_dynarray *array) {
-+    pa_assert(array);
-+
-+    while (array->n_entries > 0)
-+        pa_dynarray_remove_last(array);
-+}
-+
- unsigned pa_dynarray_size(pa_dynarray *array) {
-     pa_assert(array);
-diff --git a/src/pulsecore/dynarray.h b/src/pulsecore/dynarray.h
-index fd91433..439f181 100644
---- a/src/pulsecore/dynarray.h
-+++ b/src/pulsecore/dynarray.h
-@@ -58,6 +58,8 @@ int pa_dynarray_remove_last(pa_dynarray *array);
- /* Returns the removed item, or NULL if the array is empty. */
- void *pa_dynarray_steal_last(pa_dynarray *array);
-+void pa_dynarray_remove_all(pa_dynarray *array);
-+
- unsigned pa_dynarray_size(pa_dynarray *array);
- void * const *pa_dynarray_get_raw_array(pa_dynarray *array);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0060-hashmap-Add-pa_hashmap_remove_and_free.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0060-hashmap-Add-pa_hashmap_remove_and_free.patch
deleted file mode 100644 (file)
index 09ab108..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 26 Mar 2014 13:58:40 +0200
-Subject: hashmap: Add pa_hashmap_remove_and_free()
-
-Change-Id: Ia3530c29cecf8964989aec4f0527fc982e80e34a
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/hashmap.c | 13 +++++++++++++
- src/pulsecore/hashmap.h |  7 +++++++
- 2 files changed, 20 insertions(+)
-
-diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c
-index acac1e0..2cc03cb 100644
---- a/src/pulsecore/hashmap.c
-+++ b/src/pulsecore/hashmap.c
-@@ -207,6 +207,19 @@ void* pa_hashmap_remove(pa_hashmap *h, const void *key) {
-     return data;
- }
-+int pa_hashmap_remove_and_free(pa_hashmap *h, const void *key) {
-+    void *data;
-+
-+    pa_assert(h);
-+
-+    data = pa_hashmap_remove(h, key);
-+
-+    if (data && h->value_free_func)
-+        h->value_free_func(data);
-+
-+    return data ? 0 : -1;
-+}
-+
- void pa_hashmap_remove_all(pa_hashmap *h) {
-     pa_assert(h);
-diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h
-index e42732a..8042f7b 100644
---- a/src/pulsecore/hashmap.h
-+++ b/src/pulsecore/hashmap.h
-@@ -52,6 +52,13 @@ void* pa_hashmap_get(pa_hashmap *h, const void *key);
- /* Returns the data of the entry while removing */
- void* pa_hashmap_remove(pa_hashmap *h, const void *key);
-+/* Removes the entry and frees the entry data. Returns a negative value if the
-+ * entry is not found. FIXME: This function shouldn't be needed.
-+ * pa_hashmap_remove() should free the entry data, and the current semantics of
-+ * pa_hashmap_remove() should be implemented by a function called
-+ * pa_hashmap_steal(). */
-+int pa_hashmap_remove_and_free(pa_hashmap *h, const void *key);
-+
- /* Remove all entries but don't free the hashmap */
- void pa_hashmap_remove_all(pa_hashmap *h);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0061-device-port-Add-pa_device_port.active.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0061-device-port-Add-pa_device_port.active.patch
deleted file mode 100644 (file)
index ef71747..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 26 Mar 2014 13:41:42 +0200
-Subject: device-port: Add pa_device_port.active
-
-In the Tizen volume API, I create and delete volume control objects
-for ports based on their state (only active ports have volume
-controls). Having the pa_device_port.active flag directly accessible
-is much nicer than figuring out the state by iterating through sinks
-and checking what their active port is. It's also safer to get a
-notification for a deactivated port before the port switch is
-executed, compared to using the SINK_PORT_CHANGED hook that is fired
-only after the port switch is complete.
-
-Change-Id: I3f7f8855721c8dc3a643708a72f6e35341ff7117
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/core.h        |  1 +
- src/pulsecore/device-port.c | 15 +++++++++++++++
- src/pulsecore/device-port.h |  4 ++++
- src/pulsecore/sink.c        | 28 ++++++++++++++++++++++++----
- src/pulsecore/source.c      | 29 +++++++++++++++++++++++++----
- 5 files changed, 69 insertions(+), 8 deletions(-)
-
-diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
-index f268e42..e1cd18f 100644
---- a/src/pulsecore/core.h
-+++ b/src/pulsecore/core.h
-@@ -119,6 +119,7 @@ typedef enum pa_core_hook {
-     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;
-diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c
-index 0b65d5c..c183990 100644
---- a/src/pulsecore/device-port.c
-+++ b/src/pulsecore/device-port.c
-@@ -176,3 +176,18 @@ void pa_device_port_set_latency_offset(pa_device_port *p, int64_t offset) {
-     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, p->card->index);
-     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);
-+}
-diff --git a/src/pulsecore/device-port.h b/src/pulsecore/device-port.h
-index b10d554..2964900 100644
---- a/src/pulsecore/device-port.h
-+++ b/src/pulsecore/device-port.h
-@@ -48,6 +48,7 @@ struct pa_device_port {
-     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 */
-@@ -83,4 +84,7 @@ void pa_device_port_set_available(pa_device_port *p, pa_available_t available);
- void pa_device_port_set_latency_offset(pa_device_port *p, int64_t offset);
-+/* Called from sink.c and source.c only. */
-+void pa_device_port_active_changed(pa_device_port *port, bool new_active);
-+
- #endif
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index 61656ab..11a6e77 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -669,6 +669,9 @@ void pa_sink_put(pa_sink* s) {
-     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);
-@@ -696,6 +699,9 @@ void pa_sink_unlink(pa_sink* s) {
-     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);
-@@ -3410,6 +3416,7 @@ size_t pa_sink_get_max_request(pa_sink *s) {
- /* 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);
-@@ -3426,11 +3433,15 @@ int pa_sink_set_port(pa_sink *s, const char *name, bool save) {
-     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);
-@@ -3439,17 +3450,26 @@ int pa_sink_set_port(pa_sink *s, const char *name, bool save) {
-     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);
-diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
-index af4c6ec..d39193f 100644
---- a/src/pulsecore/source.c
-+++ b/src/pulsecore/source.c
-@@ -611,6 +611,9 @@ void pa_source_put(pa_source *s) {
-     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);
- }
-@@ -631,6 +634,9 @@ void pa_source_unlink(pa_source *s) {
-     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);
-@@ -2608,6 +2614,7 @@ size_t pa_source_get_max_rewind(pa_source *s) {
- /* 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);
-@@ -2624,11 +2631,15 @@ int pa_source_set_port(pa_source *s, const char *name, bool save) {
-     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);
-@@ -2637,16 +2648,26 @@ int pa_source_set_port(pa_source *s, const char *name, bool save) {
-     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/recipes-multimedia/pulseaudio/pulseaudio_5.0/0062-sink-source-Assign-to-reference_volume-from-only-one.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0062-sink-source-Assign-to-reference_volume-from-only-one.patch
deleted file mode 100644 (file)
index 2f5a35c..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 7 Apr 2014 12:20:58 +0300
-Subject: sink, source: Assign to reference_volume from only one place
-
-Forcing all reference volume changes to go through
-set_reference_volume_direct() makes it easier to check where the
-reference volume is changed, and it also allows us to have only one
-place where notifications for changed reference volume are sent.
-
-Change-Id: I2e769b8a2b0d7031a02446dead8ca2e0c3402751
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/sink-input.c    | 23 ++++++++++-------------
- src/pulsecore/sink.c          | 30 ++++++++++++++++++++++++++----
- src/pulsecore/sink.h          |  7 +++++++
- src/pulsecore/source-output.c | 23 ++++++++++-------------
- src/pulsecore/source.c        | 30 ++++++++++++++++++++++++++----
- src/pulsecore/source.h        |  7 +++++++
- 6 files changed, 86 insertions(+), 34 deletions(-)
-
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index d0509b3..6596eeb 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -1716,6 +1716,7 @@ int pa_sink_input_start_move(pa_sink_input *i) {
-  * their volume - this function does all that by using recursion. */
- static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
-     pa_cvolume old_volume;
-+    pa_cvolume new_volume;
-     pa_assert(i);
-     pa_assert(dest);
-@@ -1787,25 +1788,21 @@ static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
-          *         (sinks that use volume sharing should always have
-          *          soft_volume of 0 dB) */
--        old_volume = i->origin_sink->reference_volume;
--
--        i->origin_sink->reference_volume = root_sink->reference_volume;
--        pa_cvolume_remap(&i->origin_sink->reference_volume, &root_sink->channel_map, &i->origin_sink->channel_map);
-+        new_volume = root_sink->reference_volume;
-+        pa_cvolume_remap(&new_volume, &root_sink->channel_map, &i->origin_sink->channel_map);
-+        pa_sink_set_reference_volume_direct(i->origin_sink, &new_volume);
-         i->origin_sink->real_volume = root_sink->real_volume;
-         pa_cvolume_remap(&i->origin_sink->real_volume, &root_sink->channel_map, &i->origin_sink->channel_map);
-         pa_assert(pa_cvolume_is_norm(&i->origin_sink->soft_volume));
--        /* Notify others about the changed sink volume. If you wonder whether
--         * i->origin_sink->set_volume() should be called somewhere, that's not
--         * the case, because sinks that use volume sharing shouldn't have any
--         * internal volume that set_volume() would update. If you wonder
--         * whether the thread_info variables should be synced, yes, they
--         * should, and it's done by the PA_SINK_MESSAGE_FINISH_MOVE message
--         * handler. */
--        if (!pa_cvolume_equal(&i->origin_sink->reference_volume, &old_volume))
--            pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, i->origin_sink->index);
-+        /* If you wonder whether i->origin_sink->set_volume() should be called
-+         * somewhere, that's not the case, because sinks that use volume
-+         * sharing shouldn't have any internal volume that set_volume() would
-+         * update. If you wonder whether the thread_info variables should be
-+         * synced, yes, they should, and it's done by the
-+         * PA_SINK_MESSAGE_FINISH_MOVE message handler. */
-         /* Recursively update origin sink inputs. */
-         PA_IDXSET_FOREACH(origin_sink_input, i->origin_sink->inputs, idx)
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index 11a6e77..e00dce5 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -2017,13 +2017,11 @@ static bool update_reference_volume(pa_sink *s, const pa_cvolume *v, const pa_ch
-     pa_cvolume_remap(&volume, channel_map, &s->channel_map);
-     reference_volume_changed = !pa_cvolume_equal(&volume, &s->reference_volume);
--    s->reference_volume = volume;
-+    pa_sink_set_reference_volume_direct(s, &volume);
-     s->save_volume = (!reference_volume_changed && s->save_volume) || save;
--    if (reference_volume_changed)
--        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
--    else if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
-+    if (!reference_volume_changed && !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
-         /* If the root sink's volume doesn't change, then there can't be any
-          * changes in the other sinks in the sink tree either.
-          *
-@@ -3905,3 +3903,27 @@ done:
-     return out_formats;
- }
-+
-+/* Called from the main thread. */
-+void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume) {
-+    pa_cvolume old_volume;
-+    char old_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+    char new_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+
-+    pa_assert(s);
-+    pa_assert(volume);
-+
-+    old_volume = s->reference_volume;
-+
-+    if (pa_cvolume_equal(volume, &old_volume))
-+        return;
-+
-+    s->reference_volume = *volume;
-+    pa_log_debug("The reference volume of sink %s changed from %s to %s.", s->name,
-+                 pa_cvolume_snprint_verbose(old_volume_str, sizeof(old_volume_str), &old_volume, &s->channel_map,
-+                                            s->flags & PA_SINK_DECIBEL_VOLUME),
-+                 pa_cvolume_snprint_verbose(new_volume_str, sizeof(new_volume_str), volume, &s->channel_map,
-+                                            s->flags & PA_SINK_DECIBEL_VOLUME));
-+
-+    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-+}
-diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
-index 576f34b..41a439b 100644
---- a/src/pulsecore/sink.h
-+++ b/src/pulsecore/sink.h
-@@ -512,6 +512,13 @@ void pa_sink_invalidate_requested_latency(pa_sink *s, bool dynamic);
- pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s);
-+/* Called from the main thread, from sink-input.c only. The normal way to set
-+ * the sink reference volume is to call pa_sink_set_volume(), but the flat
-+ * volume logic in sink-input.c needs also a function that doesn't do all the
-+ * extra stuff that pa_sink_set_volume() does. This function simply sets
-+ * s->reference_volume and fires change notifications. */
-+void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume);
-+
- /* Verify that we called in IO context (aka 'thread context), or that
-  * the sink is not yet set up, i.e. the thread not set up yet. See
-  * pa_assert_io_context() in thread-mq.h for more information. */
-diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
-index b12758a..169d98d 100644
---- a/src/pulsecore/source-output.c
-+++ b/src/pulsecore/source-output.c
-@@ -1263,6 +1263,7 @@ int pa_source_output_start_move(pa_source_output *o) {
-  * their volume - this function does all that by using recursion. */
- static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) {
-     pa_cvolume old_volume;
-+    pa_cvolume new_volume;
-     pa_assert(o);
-     pa_assert(dest);
-@@ -1336,25 +1337,21 @@ static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) {
-          *         (sources that use volume sharing should always have
-          *          soft_volume of 0 dB) */
--        old_volume = o->destination_source->reference_volume;
--
--        o->destination_source->reference_volume = root_source->reference_volume;
--        pa_cvolume_remap(&o->destination_source->reference_volume, &root_source->channel_map, &o->destination_source->channel_map);
-+        new_volume = root_source->reference_volume;
-+        pa_cvolume_remap(&new_volume, &root_source->channel_map, &o->destination_source->channel_map);
-+        pa_source_set_reference_volume_direct(o->destination_source, &new_volume);
-         o->destination_source->real_volume = root_source->real_volume;
-         pa_cvolume_remap(&o->destination_source->real_volume, &root_source->channel_map, &o->destination_source->channel_map);
-         pa_assert(pa_cvolume_is_norm(&o->destination_source->soft_volume));
--        /* Notify others about the changed source volume. If you wonder whether
--         * o->destination_source->set_volume() should be called somewhere, that's not
--         * the case, because sources that use volume sharing shouldn't have any
--         * internal volume that set_volume() would update. If you wonder
--         * whether the thread_info variables should be synced, yes, they
--         * should, and it's done by the PA_SOURCE_MESSAGE_FINISH_MOVE message
--         * handler. */
--        if (!pa_cvolume_equal(&o->destination_source->reference_volume, &old_volume))
--            pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, o->destination_source->index);
-+        /* If you wonder whether o->destination_source->set_volume() should be
-+         * called somewhere, that's not the case, because sources that use
-+         * volume sharing shouldn't have any internal volume that set_volume()
-+         * would update. If you wonder whether the thread_info variables should
-+         * be synced, yes, they should, and it's done by the
-+         * PA_SOURCE_MESSAGE_FINISH_MOVE message handler. */
-         /* Recursively update origin source outputs. */
-         PA_IDXSET_FOREACH(destination_source_output, o->destination_source->outputs, idx)
-diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
-index d39193f..f58bb44 100644
---- a/src/pulsecore/source.c
-+++ b/src/pulsecore/source.c
-@@ -1562,13 +1562,11 @@ static bool update_reference_volume(pa_source *s, const pa_cvolume *v, const pa_
-     pa_cvolume_remap(&volume, channel_map, &s->channel_map);
-     reference_volume_changed = !pa_cvolume_equal(&volume, &s->reference_volume);
--    s->reference_volume = volume;
-+    pa_source_set_reference_volume_direct(s, &volume);
-     s->save_volume = (!reference_volume_changed && s->save_volume) || save;
--    if (reference_volume_changed)
--        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
--    else if (!(s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER))
-+    if (!reference_volume_changed && !(s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER))
-         /* If the root source's volume doesn't change, then there can't be any
-          * changes in the other source in the source tree either.
-          *
-@@ -2899,3 +2897,27 @@ done:
-     return out_formats;
- }
-+
-+/* Called from the main thread. */
-+void pa_source_set_reference_volume_direct(pa_source *s, const pa_cvolume *volume) {
-+    pa_cvolume old_volume;
-+    char old_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+    char new_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+
-+    pa_assert(s);
-+    pa_assert(volume);
-+
-+    old_volume = s->reference_volume;
-+
-+    if (pa_cvolume_equal(volume, &old_volume))
-+        return;
-+
-+    s->reference_volume = *volume;
-+    pa_log_debug("The reference volume of source %s changed from %s to %s.", s->name,
-+                 pa_cvolume_snprint_verbose(old_volume_str, sizeof(old_volume_str), &old_volume, &s->channel_map,
-+                                            s->flags & PA_SOURCE_DECIBEL_VOLUME),
-+                 pa_cvolume_snprint_verbose(new_volume_str, sizeof(new_volume_str), volume, &s->channel_map,
-+                                            s->flags & PA_SOURCE_DECIBEL_VOLUME));
-+
-+    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-+}
-diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
-index 5c74a51..6318595 100644
---- a/src/pulsecore/source.h
-+++ b/src/pulsecore/source.h
-@@ -426,6 +426,13 @@ bool pa_source_volume_change_apply(pa_source *s, pa_usec_t *usec_to_next);
- void pa_source_invalidate_requested_latency(pa_source *s, bool dynamic);
- pa_usec_t pa_source_get_latency_within_thread(pa_source *s);
-+/* Called from the main thread, from source-output.c only. The normal way to
-+ * set the source reference volume is to call pa_source_set_volume(), but the
-+ * flat volume logic in source-output.c needs also a function that doesn't do
-+ * all the extra stuff that pa_source_set_volume() does. This function simply
-+ * sets s->reference_volume and fires change notifications. */
-+void pa_source_set_reference_volume_direct(pa_source *s, const pa_cvolume *volume);
-+
- #define pa_source_assert_io_context(s) \
-     pa_assert(pa_thread_mq_get() || !PA_SOURCE_IS_LINKED((s)->state))
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0063-sink-input-source-output-Assign-to-volume-from-only-.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0063-sink-input-source-output-Assign-to-volume-from-only-.patch
deleted file mode 100644 (file)
index 38b3293..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 7 Apr 2014 12:48:15 +0300
-Subject: sink-input, source-output: Assign to volume from only one place
-
-Forcing all volume changes to go through set_volume_direct() makes
-it easier to check where the stream volume is changed, and it also
-allows us to have only one place where notifications for changed
-volume are sent.
-
-Change-Id: Ie61bcc5747b419bb83c19a3ed78fd9f4d8a73cce
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/sink-input.c    | 69 +++++++++++++++++++++----------------------
- src/pulsecore/sink-input.h    |  7 +++++
- src/pulsecore/sink.c          | 53 +++++++++------------------------
- src/pulsecore/source-output.c | 62 ++++++++++++++++++++------------------
- src/pulsecore/source-output.h |  7 +++++
- src/pulsecore/source.c        | 54 +++++++++------------------------
- 6 files changed, 108 insertions(+), 144 deletions(-)
-
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index 6596eeb..83a0493 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -1292,7 +1292,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, bool s
-         return;
-     }
--    i->volume = *volume;
-+    pa_sink_input_set_volume_direct(i, volume);
-     i->save_volume = save;
-     if (pa_sink_flat_volume_enabled(i->sink)) {
-@@ -1310,13 +1310,6 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, bool s
-         /* Copy the new soft_volume to the thread_info struct */
-         pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
-     }
--
--    /* The volume changed, let's tell people so */
--    if (i->volume_changed)
--        i->volume_changed(i);
--
--    /* The virtual volume changed, let's tell people so */
--    pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
- }
- void pa_sink_input_add_volume_factor(pa_sink_input *i, const char *key, const pa_cvolume *volume_factor) {
-@@ -1715,7 +1708,6 @@ int pa_sink_input_start_move(pa_sink_input *i) {
-  * then also the origin sink and all streams connected to it need to update
-  * their volume - this function does all that by using recursion. */
- static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
--    pa_cvolume old_volume;
-     pa_cvolume new_volume;
-     pa_assert(i);
-@@ -1765,19 +1757,11 @@ static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
-              *          always have volume_factor as soft_volume, so no change
-              *          should be needed) */
--            old_volume = i->volume;
--            pa_cvolume_reset(&i->volume, i->volume.channels);
-+            pa_cvolume_reset(&new_volume, i->volume.channels);
-+            pa_sink_input_set_volume_direct(i, &new_volume);
-             pa_cvolume_reset(&i->reference_ratio, i->reference_ratio.channels);
-             pa_assert(pa_cvolume_is_norm(&i->real_ratio));
-             pa_assert(pa_cvolume_equal(&i->soft_volume, &i->volume_factor));
--
--            /* Notify others about the changed sink input volume. */
--            if (!pa_cvolume_equal(&i->volume, &old_volume)) {
--                if (i->volume_changed)
--                    i->volume_changed(i);
--
--                pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
--            }
-         }
-         /* Additionally, the origin sink volume needs updating:
-@@ -1809,8 +1793,6 @@ static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
-             update_volume_due_to_moving(origin_sink_input, dest);
-     } else {
--        old_volume = i->volume;
--
-         if (pa_sink_flat_volume_enabled(i->sink)) {
-             /* Ok, so this is a regular stream, and flat volume is enabled. The
-              * volume will have to be updated as follows:
-@@ -1822,9 +1804,10 @@ static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
-              *     i->soft_volume := i->real_ratio * i->volume_factor
-              *         (handled later by pa_sink_set_volume) */
--            i->volume = i->sink->reference_volume;
--            pa_cvolume_remap(&i->volume, &i->sink->channel_map, &i->channel_map);
--            pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
-+            new_volume = i->sink->reference_volume;
-+            pa_cvolume_remap(&new_volume, &i->sink->channel_map, &i->channel_map);
-+            pa_sw_cvolume_multiply(&new_volume, &new_volume, &i->reference_ratio);
-+            pa_sink_input_set_volume_direct(i, &new_volume);
-         } else {
-             /* Ok, so this is a regular stream, and flat volume is disabled.
-@@ -1835,21 +1818,10 @@ static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
-              *     i->real_ratio := i->reference_ratio
-              *     i->soft_volume := i->real_ratio * i->volume_factor */
--            i->volume = i->reference_ratio;
-+            pa_sink_input_set_volume_direct(i, &i->reference_ratio);
-             i->real_ratio = i->reference_ratio;
-             pa_sw_cvolume_multiply(&i->soft_volume, &i->real_ratio, &i->volume_factor);
-         }
--
--        /* Notify others about the changed sink input volume. */
--        if (!pa_cvolume_equal(&i->volume, &old_volume)) {
--            /* XXX: In case i->sink has flat volume enabled, then real_ratio
--             * and soft_volume are not updated yet. Let's hope that the
--             * callback implementation doesn't care about those variables... */
--            if (i->volume_changed)
--                i->volume_changed(i);
--
--            pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
--        }
-     }
-     /* If i->sink == dest, then recursion has finished, and we can finally call
-@@ -2333,3 +2305,28 @@ int pa_sink_input_update_rate(pa_sink_input *i) {
-     return 0;
- }
-+
-+/* Called from the main thread. */
-+void pa_sink_input_set_volume_direct(pa_sink_input *i, const pa_cvolume *volume) {
-+    pa_cvolume old_volume;
-+    char old_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+    char new_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+
-+    pa_assert(i);
-+    pa_assert(volume);
-+
-+    old_volume = i->volume;
-+
-+    if (pa_cvolume_equal(volume, &old_volume))
-+        return;
-+
-+    i->volume = *volume;
-+    pa_log_debug("The volume of sink input %u changed from %s to %s.", i->index,
-+                 pa_cvolume_snprint_verbose(old_volume_str, sizeof(old_volume_str), &old_volume, &i->channel_map, true),
-+                 pa_cvolume_snprint_verbose(new_volume_str, sizeof(new_volume_str), volume, &i->channel_map, true));
-+
-+    if (i->volume_changed)
-+        i->volume_changed(i);
-+
-+    pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
-+}
-diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
-index deea348..4e7b229 100644
---- a/src/pulsecore/sink-input.h
-+++ b/src/pulsecore/sink-input.h
-@@ -431,6 +431,13 @@ bool pa_sink_input_process_underrun(pa_sink_input *i);
- pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret);
-+/* Called from the main thread, from sink.c only. The normal way to set the
-+ * sink input volume is to call pa_sink_input_set_volume(), but the flat volume
-+ * logic in sink.c needs also a function that doesn't do all the extra stuff
-+ * that pa_sink_input_set_volume() does. This function simply sets i->volume
-+ * and fires change notifications. */
-+void pa_sink_input_set_volume_direct(pa_sink_input *i, const pa_cvolume *volume);
-+
- #define pa_sink_input_assert_io_context(s) \
-     pa_assert(pa_thread_mq_get() || !PA_SINK_INPUT_IS_LINKED((s)->state))
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index e00dce5..94046b1 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -1898,20 +1898,13 @@ static void update_real_volume(pa_sink *s, const pa_cvolume *new_volume, pa_chan
-     PA_IDXSET_FOREACH(i, s->inputs, idx) {
-         if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
-             if (pa_sink_flat_volume_enabled(s)) {
--                pa_cvolume old_volume = i->volume;
-+                pa_cvolume new_input_volume;
-                 /* Follow the root sink's real volume. */
--                i->volume = *new_volume;
--                pa_cvolume_remap(&i->volume, channel_map, &i->channel_map);
-+                new_input_volume = *new_volume;
-+                pa_cvolume_remap(&new_input_volume, channel_map, &i->channel_map);
-+                pa_sink_input_set_volume_direct(i, &new_input_volume);
-                 compute_reference_ratio(i);
--
--                /* The volume changed, let's tell people so */
--                if (!pa_cvolume_equal(&old_volume, &i->volume)) {
--                    if (i->volume_changed)
--                        i->volume_changed(i);
--
--                    pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
--                }
-             }
-             update_real_volume(i->origin_sink, new_volume, channel_map);
-@@ -1966,7 +1959,7 @@ static void propagate_reference_volume(pa_sink *s) {
-      * sink input volumes accordingly */
-     PA_IDXSET_FOREACH(i, s->inputs, idx) {
--        pa_cvolume old_volume;
-+        pa_cvolume new_volume;
-         if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
-             propagate_reference_volume(i->origin_sink);
-@@ -1977,24 +1970,14 @@ static void propagate_reference_volume(pa_sink *s) {
-             continue;
-         }
--        old_volume = i->volume;
--
-         /* This basically calculates:
-          *
-          * i->volume := s->reference_volume * i->reference_ratio  */
--        i->volume = s->reference_volume;
--        pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map);
--        pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
--
--        /* The volume changed, let's tell people so */
--        if (!pa_cvolume_equal(&old_volume, &i->volume)) {
--
--            if (i->volume_changed)
--                i->volume_changed(i);
--
--            pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
--        }
-+        new_volume = s->reference_volume;
-+        pa_cvolume_remap(&new_volume, &s->channel_map, &i->channel_map);
-+        pa_sw_cvolume_multiply(&new_volume, &new_volume, &i->reference_ratio);
-+        pa_sink_input_set_volume_direct(i, &new_volume);
-     }
- }
-@@ -2215,7 +2198,7 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
-     if (pa_sink_flat_volume_enabled(s)) {
-         PA_IDXSET_FOREACH(i, s->inputs, idx) {
--            pa_cvolume old_volume = i->volume;
-+            pa_cvolume new_volume;
-             /* 2. Since the sink's reference and real volumes are equal
-              * now our ratios should be too. */
-@@ -2229,18 +2212,10 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
-              * i->volume = s->reference_volume * i->reference_ratio
-              *
-              * This is identical to propagate_reference_volume() */
--            i->volume = s->reference_volume;
--            pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map);
--            pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
--
--            /* Notify if something changed */
--            if (!pa_cvolume_equal(&old_volume, &i->volume)) {
--
--                if (i->volume_changed)
--                    i->volume_changed(i);
--
--                pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
--            }
-+            new_volume = s->reference_volume;
-+            pa_cvolume_remap(&new_volume, &s->channel_map, &i->channel_map);
-+            pa_sw_cvolume_multiply(&new_volume, &new_volume, &i->reference_ratio);
-+            pa_sink_input_set_volume_direct(i, &new_volume);
-             if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
-                 propagate_real_volume(i->origin_sink, old_real_volume);
-diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
-index 169d98d..761323e 100644
---- a/src/pulsecore/source-output.c
-+++ b/src/pulsecore/source-output.c
-@@ -972,7 +972,7 @@ void pa_source_output_set_volume(pa_source_output *o, const pa_cvolume *volume,
-         return;
-     }
--    o->volume = *volume;
-+    pa_source_output_set_volume_direct(o, volume);
-     o->save_volume = save;
-     if (pa_source_flat_volume_enabled(o->source)) {
-@@ -1262,7 +1262,6 @@ int pa_source_output_start_move(pa_source_output *o) {
-  * then also the origin source and all streams connected to it need to update
-  * their volume - this function does all that by using recursion. */
- static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) {
--    pa_cvolume old_volume;
-     pa_cvolume new_volume;
-     pa_assert(o);
-@@ -1314,19 +1313,11 @@ static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) {
-              *          always have volume_factor as soft_volume, so no change
-              *          should be needed) */
--            old_volume = o->volume;
--            pa_cvolume_reset(&o->volume, o->volume.channels);
-+            pa_cvolume_reset(&new_volume, o->volume.channels);
-+            pa_source_output_set_volume_direct(o, &new_volume);
-             pa_cvolume_reset(&o->reference_ratio, o->reference_ratio.channels);
-             pa_assert(pa_cvolume_is_norm(&o->real_ratio));
-             pa_assert(pa_cvolume_equal(&o->soft_volume, &o->volume_factor));
--
--            /* Notify others about the changed source output volume. */
--            if (!pa_cvolume_equal(&o->volume, &old_volume)) {
--                if (o->volume_changed)
--                    o->volume_changed(o);
--
--                pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
--            }
-         }
-         /* Additionally, the origin source volume needs updating:
-@@ -1358,8 +1349,6 @@ static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) {
-             update_volume_due_to_moving(destination_source_output, dest);
-     } else {
--        old_volume = o->volume;
--
-         if (pa_source_flat_volume_enabled(o->source)) {
-             /* Ok, so this is a regular stream, and flat volume is enabled. The
-              * volume will have to be updated as follows:
-@@ -1371,9 +1360,10 @@ static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) {
-              *     o->soft_volume := o->real_ratio * o->volume_factor
-              *         (handled later by pa_source_set_volume) */
--            o->volume = o->source->reference_volume;
--            pa_cvolume_remap(&o->volume, &o->source->channel_map, &o->channel_map);
--            pa_sw_cvolume_multiply(&o->volume, &o->volume, &o->reference_ratio);
-+            new_volume = o->source->reference_volume;
-+            pa_cvolume_remap(&new_volume, &o->source->channel_map, &o->channel_map);
-+            pa_sw_cvolume_multiply(&new_volume, &new_volume, &o->reference_ratio);
-+            pa_source_output_set_volume_direct(o, &new_volume);
-         } else {
-             /* Ok, so this is a regular stream, and flat volume is disabled.
-@@ -1384,21 +1374,10 @@ static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) {
-              *     o->real_ratio := o->reference_ratio
-              *     o->soft_volume := o->real_ratio * o->volume_factor */
--            o->volume = o->reference_ratio;
-+            pa_source_output_set_volume_direct(o, &o->reference_ratio);
-             o->real_ratio = o->reference_ratio;
-             pa_sw_cvolume_multiply(&o->soft_volume, &o->real_ratio, &o->volume_factor);
-         }
--
--        /* Notify others about the changed source output volume. */
--        if (!pa_cvolume_equal(&o->volume, &old_volume)) {
--            /* XXX: In case o->source has flat volume enabled, then real_ratio
--             * and soft_volume are not updated yet. Let's hope that the
--             * callback implementation doesn't care about those variables... */
--            if (o->volume_changed)
--                o->volume_changed(o);
--
--            pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
--        }
-     }
-     /* If o->source == dest, then recursion has finished, and we can finally call
-@@ -1692,3 +1671,28 @@ int pa_source_output_update_rate(pa_source_output *o) {
-     return 0;
- }
-+
-+/* Called from the main thread. */
-+void pa_source_output_set_volume_direct(pa_source_output *o, const pa_cvolume *volume) {
-+    pa_cvolume old_volume;
-+    char old_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+    char new_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+
-+    pa_assert(o);
-+    pa_assert(volume);
-+
-+    old_volume = o->volume;
-+
-+    if (pa_cvolume_equal(volume, &old_volume))
-+        return;
-+
-+    o->volume = *volume;
-+    pa_log_debug("The volume of source output %u changed from %s to %s.", o->index,
-+                 pa_cvolume_snprint_verbose(old_volume_str, sizeof(old_volume_str), &old_volume, &o->channel_map, true),
-+                 pa_cvolume_snprint_verbose(new_volume_str, sizeof(new_volume_str), volume, &o->channel_map, true));
-+
-+    if (o->volume_changed)
-+        o->volume_changed(o);
-+
-+    pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
-+}
-diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
-index 102fb8b..27d6fd4 100644
---- a/src/pulsecore/source-output.h
-+++ b/src/pulsecore/source-output.h
-@@ -353,6 +353,13 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int
- pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec);
-+/* Called from the main thread, from source.c only. The normal way to set the
-+ * source output volume is to call pa_source_output_set_volume(), but the flat
-+ * volume logic in source.c needs also a function that doesn't do all the extra
-+ * stuff that pa_source_output_set_volume() does. This function simply sets
-+ * o->volume and fires change notifications. */
-+void pa_source_output_set_volume_direct(pa_source_output *o, const pa_cvolume *volume);
-+
- #define pa_source_output_assert_io_context(s) \
-     pa_assert(pa_thread_mq_get() || !PA_SOURCE_OUTPUT_IS_LINKED((s)->state))
-diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
-index f58bb44..c8165e6 100644
---- a/src/pulsecore/source.c
-+++ b/src/pulsecore/source.c
-@@ -1443,20 +1443,13 @@ static void update_real_volume(pa_source *s, const pa_cvolume *new_volume, pa_ch
-     PA_IDXSET_FOREACH(o, s->outputs, idx) {
-         if (o->destination_source && (o->destination_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)) {
-             if (pa_source_flat_volume_enabled(s)) {
--                pa_cvolume old_volume = o->volume;
-+                pa_cvolume new_output_volume;
-                 /* Follow the root source's real volume. */
--                o->volume = *new_volume;
--                pa_cvolume_remap(&o->volume, channel_map, &o->channel_map);
-+                new_output_volume = *new_volume;
-+                pa_cvolume_remap(&new_output_volume, channel_map, &o->channel_map);
-+                pa_source_output_set_volume_direct(o, &new_output_volume);
-                 compute_reference_ratio(o);
--
--                /* The volume changed, let's tell people so */
--                if (!pa_cvolume_equal(&old_volume, &o->volume)) {
--                    if (o->volume_changed)
--                        o->volume_changed(o);
--
--                    pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
--                }
-             }
-             update_real_volume(o->destination_source, new_volume, channel_map);
-@@ -1511,7 +1504,7 @@ static void propagate_reference_volume(pa_source *s) {
-      * source output volumes accordingly */
-     PA_IDXSET_FOREACH(o, s->outputs, idx) {
--        pa_cvolume old_volume;
-+        pa_cvolume new_volume;
-         if (o->destination_source && (o->destination_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)) {
-             propagate_reference_volume(o->destination_source);
-@@ -1522,24 +1515,14 @@ static void propagate_reference_volume(pa_source *s) {
-             continue;
-         }
--        old_volume = o->volume;
--
-         /* This basically calculates:
-          *
-          * o->volume := o->reference_volume * o->reference_ratio  */
--        o->volume = s->reference_volume;
--        pa_cvolume_remap(&o->volume, &s->channel_map, &o->channel_map);
--        pa_sw_cvolume_multiply(&o->volume, &o->volume, &o->reference_ratio);
--
--        /* The volume changed, let's tell people so */
--        if (!pa_cvolume_equal(&old_volume, &o->volume)) {
--
--            if (o->volume_changed)
--                o->volume_changed(o);
--
--            pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
--        }
-+        new_volume = s->reference_volume;
-+        pa_cvolume_remap(&new_volume, &s->channel_map, &o->channel_map);
-+        pa_sw_cvolume_multiply(&new_volume, &new_volume, &o->reference_ratio);
-+        pa_source_output_set_volume_direct(o, &new_volume);
-     }
- }
-@@ -1732,9 +1715,8 @@ static void propagate_real_volume(pa_source *s, const pa_cvolume *old_real_volum
-     }
-     if (pa_source_flat_volume_enabled(s)) {
--
-         PA_IDXSET_FOREACH(o, s->outputs, idx) {
--            pa_cvolume old_volume = o->volume;
-+            pa_cvolume new_volume;
-             /* 2. Since the source's reference and real volumes are equal
-              * now our ratios should be too. */
-@@ -1748,18 +1730,10 @@ static void propagate_real_volume(pa_source *s, const pa_cvolume *old_real_volum
-              * o->volume = s->reference_volume * o->reference_ratio
-              *
-              * This is identical to propagate_reference_volume() */
--            o->volume = s->reference_volume;
--            pa_cvolume_remap(&o->volume, &s->channel_map, &o->channel_map);
--            pa_sw_cvolume_multiply(&o->volume, &o->volume, &o->reference_ratio);
--
--            /* Notify if something changed */
--            if (!pa_cvolume_equal(&old_volume, &o->volume)) {
--
--                if (o->volume_changed)
--                    o->volume_changed(o);
--
--                pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
--            }
-+            new_volume = s->reference_volume;
-+            pa_cvolume_remap(&new_volume, &s->channel_map, &o->channel_map);
-+            pa_sw_cvolume_multiply(&new_volume, &new_volume, &o->reference_ratio);
-+            pa_source_output_set_volume_direct(o, &new_volume);
-             if (o->destination_source && (o->destination_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER))
-                 propagate_real_volume(o->destination_source, old_real_volume);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0064-sink-source-Return-early-from-set_mute.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0064-sink-source-Return-early-from-set_mute.patch
deleted file mode 100644 (file)
index 4cd0fdb..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 14 Apr 2014 14:03:24 +0300
-Subject: sink, source: Return early from set_mute()
-
-This avoids redundant set_mute() callback calls.
-
-Some logging was added too.
-
-Change-Id: I10188c3b43d61fe751abe0f9940015af35c4a137
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/sink.c   | 13 +++++++++----
- src/pulsecore/source.c | 13 +++++++++----
- 2 files changed, 18 insertions(+), 8 deletions(-)
-
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index 94046b1..3eed550 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -2288,16 +2288,21 @@ void pa_sink_set_mute(pa_sink *s, bool mute, bool save) {
-     pa_assert(PA_SINK_IS_LINKED(s->state));
-     old_muted = s->muted;
-+
-+    if (mute == old_muted) {
-+        s->save_muted |= save;
-+        return;
-+    }
-+
-     s->muted = mute;
--    s->save_muted = (old_muted == s->muted && s->save_muted) || save;
-+    s->save_muted = save;
-     if (!(s->flags & PA_SINK_DEFERRED_VOLUME) && s->set_mute)
-         s->set_mute(s);
-+    pa_log_debug("The mute of sink %s changed from %s to %s.", s->name, pa_yes_no(old_muted), pa_yes_no(mute));
-     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
--
--    if (old_muted != s->muted)
--        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-+    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
- }
- /* Called from main thread */
-diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
-index c8165e6..4f4aea3 100644
---- a/src/pulsecore/source.c
-+++ b/src/pulsecore/source.c
-@@ -1806,16 +1806,21 @@ void pa_source_set_mute(pa_source *s, bool mute, bool save) {
-     pa_assert(PA_SOURCE_IS_LINKED(s->state));
-     old_muted = s->muted;
-+
-+    if (mute == old_muted) {
-+        s->save_muted |= save;
-+        return;
-+    }
-+
-     s->muted = mute;
--    s->save_muted = (old_muted == s->muted && s->save_muted) || save;
-+    s->save_muted = save;
-     if (!(s->flags & PA_SOURCE_DEFERRED_VOLUME) && s->set_mute)
-         s->set_mute(s);
-+    pa_log_debug("The mute of source %s changed from %s to %s.", s->name, pa_yes_no(old_muted), pa_yes_no(mute));
-     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
--
--    if (old_muted != s->muted)
--        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-+    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
- }
- /* Called from main thread */
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0065-sink-input-source-output-Add-logging-to-set_mute.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0065-sink-input-source-output-Add-logging-to-set_mute.patch
deleted file mode 100644 (file)
index a60d1d2..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 14 Apr 2014 14:13:56 +0300
-Subject: sink-input, source-output: Add logging to set_mute()
-
-Change-Id: Ie10aa76cae75c7b6a52ea4a9039b8e3e37a748b2
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/sink-input.c    | 8 +++++++-
- src/pulsecore/source-output.c | 8 +++++++-
- 2 files changed, 14 insertions(+), 2 deletions(-)
-
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index 83a0493..f706acc 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -1458,16 +1458,22 @@ pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, bool
- /* Called from main context */
- void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save) {
-+    bool old_mute;
-+
-     pa_sink_input_assert_ref(i);
-     pa_assert_ctl_context();
-     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
--    if (!i->muted == !mute) {
-+    old_mute = i->muted;
-+
-+    if (mute == old_mute) {
-         i->save_muted |= save;
-         return;
-     }
-     i->muted = mute;
-+    pa_log_debug("The mute of sink input %u changed from %s to %s.", i->index, pa_yes_no(old_mute), pa_yes_no(mute));
-+
-     i->save_muted = save;
-     pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE, NULL, 0, NULL) == 0);
-diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
-index 761323e..bb89384 100644
---- a/src/pulsecore/source-output.c
-+++ b/src/pulsecore/source-output.c
-@@ -1057,16 +1057,22 @@ pa_cvolume *pa_source_output_get_volume(pa_source_output *o, pa_cvolume *volume,
- /* Called from main context */
- void pa_source_output_set_mute(pa_source_output *o, bool mute, bool save) {
-+    bool old_mute;
-+
-     pa_source_output_assert_ref(o);
-     pa_assert_ctl_context();
-     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
--    if (!o->muted == !mute) {
-+    old_mute = o->muted;
-+
-+    if (mute == old_mute) {
-         o->save_muted |= save;
-         return;
-     }
-     o->muted = mute;
-+    pa_log_debug("The mute of source output %u changed from %s to %s.", o->index, pa_yes_no(old_mute), pa_yes_no(mute));
-+
-     o->save_muted = save;
-     pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_SOFT_MUTE, NULL, 0, NULL) == 0);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0066-sink-source-Allow-calling-set_mute-during-initializa.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0066-sink-source-Allow-calling-set_mute-during-initializa.patch
deleted file mode 100644 (file)
index 02ac7b5..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 14 Apr 2014 14:43:23 +0300
-Subject: sink, source: Allow calling set_mute() during initialization
-
-Currently the alsa sink and source write directly to s->muted during
-initialization, but I think it's better to avoid direct writes, and
-use the set_mute() function instead, because that makes it easier to
-figure out where s->muted is modified. This patch prevents the
-set_mute() call from crashing in the state assertion.
-
-Change-Id: I12220fb2668723931bebbe1484f115016f1edf25
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/sink.c   | 4 +++-
- src/pulsecore/source.c | 4 +++-
- 2 files changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index 3eed550..7eb4cb4 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -2285,7 +2285,6 @@ void pa_sink_set_mute(pa_sink *s, bool mute, bool save) {
-     pa_sink_assert_ref(s);
-     pa_assert_ctl_context();
--    pa_assert(PA_SINK_IS_LINKED(s->state));
-     old_muted = s->muted;
-@@ -2300,6 +2299,9 @@ void pa_sink_set_mute(pa_sink *s, bool mute, bool save) {
-     if (!(s->flags & PA_SINK_DEFERRED_VOLUME) && s->set_mute)
-         s->set_mute(s);
-+    if (!PA_SINK_IS_LINKED(s->state))
-+        return;
-+
-     pa_log_debug("The mute of sink %s changed from %s to %s.", s->name, pa_yes_no(old_muted), pa_yes_no(mute));
-     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
-     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
-index 4f4aea3..3b6ad44 100644
---- a/src/pulsecore/source.c
-+++ b/src/pulsecore/source.c
-@@ -1803,7 +1803,6 @@ void pa_source_set_mute(pa_source *s, bool mute, bool save) {
-     pa_source_assert_ref(s);
-     pa_assert_ctl_context();
--    pa_assert(PA_SOURCE_IS_LINKED(s->state));
-     old_muted = s->muted;
-@@ -1818,6 +1817,9 @@ void pa_source_set_mute(pa_source *s, bool mute, bool save) {
-     if (!(s->flags & PA_SOURCE_DEFERRED_VOLUME) && s->set_mute)
-         s->set_mute(s);
-+    if (!PA_SOURCE_IS_LINKED(s->state))
-+        return;
-+
-     pa_log_debug("The mute of source %s changed from %s to %s.", s->name, pa_yes_no(old_muted), pa_yes_no(mute));
-     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
-     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0067-echo-cancel-Remove-redundant-get_mute-callback.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0067-echo-cancel-Remove-redundant-get_mute-callback.patch
deleted file mode 100644 (file)
index 4962b8d..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 14 Apr 2014 15:13:08 +0300
-Subject: echo-cancel: Remove redundant get_mute() callback
-
-The callback just called pa_source_output_get_mute(), which doesn't
-have any side effects, and the return value wasn't used either, so
-the callback was essentially a no-op.
-
-Change-Id: Ic16824b06393f59b55087842da64c7d09035b9e8
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/echo-cancel/module-echo-cancel.c | 15 ---------------
- 1 file changed, 15 deletions(-)
-
-diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
-index 29eed13..8f791ce 100644
---- a/src/modules/echo-cancel/module-echo-cancel.c
-+++ b/src/modules/echo-cancel/module-echo-cancel.c
-@@ -656,20 +656,6 @@ static void sink_set_mute_cb(pa_sink *s) {
-     pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
- }
--/* Called from main context */
--static void source_get_mute_cb(pa_source *s) {
--    struct userdata *u;
--
--    pa_source_assert_ref(s);
--    pa_assert_se(u = s->userdata);
--
--    if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
--        !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
--        return;
--
--    pa_source_output_get_mute(u->source_output);
--}
--
- /* Called from source I/O thread context. */
- static void apply_diff_time(struct userdata *u, int64_t diff_time) {
-     int64_t diff;
-@@ -1857,7 +1843,6 @@ int pa__init(pa_module*m) {
-     u->source->parent.process_msg = source_process_msg_cb;
-     u->source->set_state = source_set_state_cb;
-     u->source->update_requested_latency = source_update_requested_latency_cb;
--    pa_source_set_get_mute_callback(u->source, source_get_mute_cb);
-     pa_source_set_set_mute_callback(u->source, source_set_mute_cb);
-     if (!u->use_volume_sharing) {
-         pa_source_set_get_volume_callback(u->source, source_get_volume_cb);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0068-sink-source-Call-set_mute-from-mute_changed.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0068-sink-source-Call-set_mute-from-mute_changed.patch
deleted file mode 100644 (file)
index 42422ea..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Tue, 15 Apr 2014 09:39:49 +0300
-Subject: sink, source: Call set_mute() from mute_changed()
-
-This refactoring reduces duplication, as mute_changed() used to do the
-same things as set_mute(). Other benefits are improved logging
-(set_mute() logs the mute change, mute_changed() used to not do that)
-and the soft mute state is kept up to date, because set_mute() sends
-the SET_MUTE message to the IO thread.
-
-The set_mute_in_progress flag is an extra precaution for preventing
-recursion in case a sink/source implementation's set_mute() callback
-causes mute_changed() to be called. Currently there are no such
-implementations, but I think that would be a valid thing to do, so
-some day there might be such implementation.
-
-Change-Id: I33c81f4034001f777c4533c2c63eada67548c683
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/sink.c   | 19 ++++++++++++-------
- src/pulsecore/sink.h   |  2 ++
- src/pulsecore/source.c | 19 ++++++++++++-------
- src/pulsecore/source.h |  2 ++
- 4 files changed, 28 insertions(+), 14 deletions(-)
-
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index 7eb4cb4..4c348b5 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -2296,8 +2296,11 @@ void pa_sink_set_mute(pa_sink *s, bool mute, bool save) {
-     s->muted = mute;
-     s->save_muted = save;
--    if (!(s->flags & PA_SINK_DEFERRED_VOLUME) && s->set_mute)
-+    if (!(s->flags & PA_SINK_DEFERRED_VOLUME) && s->set_mute) {
-+        s->set_mute_in_progress = true;
-         s->set_mute(s);
-+        s->set_mute_in_progress = false;
-+    }
-     if (!PA_SINK_IS_LINKED(s->state))
-         return;
-@@ -2341,15 +2344,17 @@ void pa_sink_mute_changed(pa_sink *s, bool new_muted) {
-     pa_assert_ctl_context();
-     pa_assert(PA_SINK_IS_LINKED(s->state));
--    /* The sink implementor may call this if the volume changed to make sure everyone is notified */
--
--    if (s->muted == new_muted)
-+    if (s->set_mute_in_progress)
-         return;
--    s->muted = new_muted;
--    s->save_muted = true;
-+    /* pa_sink_set_mute() does this same check, so this may appear redundant,
-+     * but we must have this here also, because the save parameter of
-+     * pa_sink_set_mute() would otherwise have unintended side effects (saving
-+     * the mute state when it shouldn't be saved). */
-+    if (new_muted == s->muted)
-+        return;
--    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-+    pa_sink_set_mute(s, new_muted, true);
- }
- /* Called from main thread */
-diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
-index 41a439b..72437a4 100644
---- a/src/pulsecore/sink.h
-+++ b/src/pulsecore/sink.h
-@@ -122,6 +122,8 @@ struct pa_sink {
-     unsigned priority;
-+    bool set_mute_in_progress;
-+
-     /* Called when the main loop requests a state change. Called from
-      * main loop context. If returns -1 the state change will be
-      * inhibited */
-diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
-index 3b6ad44..2f6aaad 100644
---- a/src/pulsecore/source.c
-+++ b/src/pulsecore/source.c
-@@ -1814,8 +1814,11 @@ void pa_source_set_mute(pa_source *s, bool mute, bool save) {
-     s->muted = mute;
-     s->save_muted = save;
--    if (!(s->flags & PA_SOURCE_DEFERRED_VOLUME) && s->set_mute)
-+    if (!(s->flags & PA_SOURCE_DEFERRED_VOLUME) && s->set_mute) {
-+        s->set_mute_in_progress = true;
-         s->set_mute(s);
-+        s->set_mute_in_progress = false;
-+    }
-     if (!PA_SOURCE_IS_LINKED(s->state))
-         return;
-@@ -1859,15 +1862,17 @@ void pa_source_mute_changed(pa_source *s, bool new_muted) {
-     pa_assert_ctl_context();
-     pa_assert(PA_SOURCE_IS_LINKED(s->state));
--    /* The source implementor may call this if the mute state changed to make sure everyone is notified */
--
--    if (s->muted == new_muted)
-+    if (s->set_mute_in_progress)
-         return;
--    s->muted = new_muted;
--    s->save_muted = true;
-+    /* pa_source_set_mute() does this same check, so this may appear redundant,
-+     * but we must have this here also, because the save parameter of
-+     * pa_source_set_mute() would otherwise have unintended side effects
-+     * (saving the mute state when it shouldn't be saved). */
-+    if (new_muted == s->muted)
-+        return;
--    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-+    pa_source_set_mute(s, new_muted, true);
- }
- /* Called from main thread */
-diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
-index 6318595..ca2ed59 100644
---- a/src/pulsecore/source.h
-+++ b/src/pulsecore/source.h
-@@ -118,6 +118,8 @@ struct pa_source {
-     unsigned priority;
-+    bool set_mute_in_progress;
-+
-     /* Called when the main loop requests a state change. Called from
-      * main loop context. If returns -1 the state change will be
-      * inhibited */
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0069-sink-source-Assign-to-s-muted-from-only-one-place.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0069-sink-source-Assign-to-s-muted-from-only-one-place.patch
deleted file mode 100644 (file)
index c7332fd..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 14 Apr 2014 14:52:16 +0300
-Subject: sink, source: Assign to s->muted from only one place
-
-Forcing all mute changes to go through set_mute() makes it easier to
-check where the muted field is changed, and it also allows us to have
-only one place where notifications for changed mute are sent.
-
-Change-Id: Idb1bd6ef923a165e249d42265ebedc30a6c8fca4
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/alsa/alsa-sink.c   | 17 ++++++++++-------
- src/modules/alsa/alsa-source.c | 17 ++++++++++-------
- src/modules/module-solaris.c   | 17 +++++++++++------
- src/pulsecore/sink.c           | 26 ++++++++++----------------
- src/pulsecore/sink.h           | 24 ++++++++++++++++++------
- src/pulsecore/source.c         | 26 ++++++++++----------------
- src/pulsecore/source.h         | 24 ++++++++++++++++++------
- 7 files changed, 87 insertions(+), 64 deletions(-)
-
-diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
-index 03babb3..2bc27ff 100644
---- a/src/modules/alsa/alsa-sink.c
-+++ b/src/modules/alsa/alsa-sink.c
-@@ -1401,18 +1401,17 @@ static void sink_write_volume_cb(pa_sink *s) {
-     }
- }
--static void sink_get_mute_cb(pa_sink *s) {
-+static int sink_get_mute_cb(pa_sink *s, bool *mute) {
-     struct userdata *u = s->userdata;
--    bool b;
-     pa_assert(u);
-     pa_assert(u->mixer_path);
-     pa_assert(u->mixer_handle);
--    if (pa_alsa_path_get_mute(u->mixer_path, u->mixer_handle, &b) < 0)
--        return;
-+    if (pa_alsa_path_get_mute(u->mixer_path, u->mixer_handle, mute) < 0)
-+        return -1;
--    s->muted = b;
-+    return 0;
- }
- static void sink_set_mute_cb(pa_sink *s) {
-@@ -2399,8 +2398,12 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
-         if (u->sink->set_mute)
-             u->sink->set_mute(u->sink);
-     } else {
--        if (u->sink->get_mute)
--            u->sink->get_mute(u->sink);
-+        if (u->sink->get_mute) {
-+            bool mute;
-+
-+            if (u->sink->get_mute(u->sink, &mute) >= 0)
-+                pa_sink_set_mute(u->sink, mute, false);
-+        }
-     }
-     if ((data.volume_is_set || data.muted_is_set) && u->sink->write_volume)
-diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
-index 2e93e0f..e181a30 100644
---- a/src/modules/alsa/alsa-source.c
-+++ b/src/modules/alsa/alsa-source.c
-@@ -1277,18 +1277,17 @@ static void source_write_volume_cb(pa_source *s) {
-     }
- }
--static void source_get_mute_cb(pa_source *s) {
-+static int source_get_mute_cb(pa_source *s, bool *mute) {
-     struct userdata *u = s->userdata;
--    bool b;
-     pa_assert(u);
-     pa_assert(u->mixer_path);
-     pa_assert(u->mixer_handle);
--    if (pa_alsa_path_get_mute(u->mixer_path, u->mixer_handle, &b) < 0)
--        return;
-+    if (pa_alsa_path_get_mute(u->mixer_path, u->mixer_handle, mute) < 0)
-+        return -1;
--    s->muted = b;
-+    return 0;
- }
- static void source_set_mute_cb(pa_source *s) {
-@@ -2088,8 +2087,12 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
-         if (u->source->set_mute)
-             u->source->set_mute(u->source);
-     } else {
--        if (u->source->get_mute)
--            u->source->get_mute(u->source);
-+        if (u->source->get_mute) {
-+            bool mute;
-+
-+            if (u->source->get_mute(u->source, &mute) >= 0)
-+                pa_source_set_mute(u->source, mute, false);
-+        }
-     }
-     if ((data.volume_is_set || data.muted_is_set) && u->source->write_volume)
-diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c
-index b4fa734..71a98e9 100644
---- a/src/modules/module-solaris.c
-+++ b/src/modules/module-solaris.c
-@@ -571,18 +571,23 @@ static void sink_set_mute(pa_sink *s) {
-     }
- }
--static void sink_get_mute(pa_sink *s) {
-+static int sink_get_mute(pa_sink *s, bool *mute) {
-     struct userdata *u = s->userdata;
-     audio_info_t info;
-     pa_assert(u);
--    if (u->fd >= 0) {
--        if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
--            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
--        else
--            s->muted = !!info.output_muted;
-+    if (u->fd < 0)
-+        return -1;
-+
-+    if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0) {
-+        pa_log("AUDIO_GETINFO: %s", pa_cstrerror(errno));
-+        return -1;
-     }
-+
-+    *mute = info.output_muted;
-+
-+    return 0;
- }
- static void process_rewind(struct userdata *u) {
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index 4c348b5..b64001b 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -519,7 +519,7 @@ void pa_sink_set_write_volume_callback(pa_sink *s, pa_sink_cb_t cb) {
-         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
- }
--void pa_sink_set_get_mute_callback(pa_sink *s, pa_sink_cb_t cb) {
-+void pa_sink_set_get_mute_callback(pa_sink *s, pa_sink_get_mute_cb_t cb) {
-     pa_assert(s);
-     s->get_mute = cb;
-@@ -2317,21 +2317,15 @@ bool pa_sink_get_mute(pa_sink *s, bool force_refresh) {
-     pa_assert_ctl_context();
-     pa_assert(PA_SINK_IS_LINKED(s->state));
--    if (s->refresh_muted || force_refresh) {
--        bool old_muted = s->muted;
-+    if ((s->refresh_muted || force_refresh) && s->get_mute) {
-+        bool mute;
--        if (!(s->flags & PA_SINK_DEFERRED_VOLUME) && s->get_mute)
--            s->get_mute(s);
--
--        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
--
--        if (old_muted != s->muted) {
--            s->save_muted = true;
--
--            pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
--
--            /* Make sure the soft mute status stays in sync */
--            pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
-+        if (s->flags & PA_SINK_DEFERRED_VOLUME) {
-+            if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &mute, 0, NULL) >= 0)
-+                pa_sink_mute_changed(s, mute);
-+        } else {
-+            if (s->get_mute(s, &mute) >= 0)
-+                pa_sink_mute_changed(s, mute);
-         }
-     }
-@@ -2848,7 +2842,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
-         case PA_SINK_MESSAGE_GET_MUTE:
-             if (s->flags & PA_SINK_DEFERRED_VOLUME && s->get_mute)
--                s->get_mute(s);
-+                return s->get_mute(s, userdata);
-             return 0;
-diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
-index 72437a4..e069d02 100644
---- a/src/pulsecore/sink.h
-+++ b/src/pulsecore/sink.h
-@@ -59,6 +59,8 @@ static inline bool PA_SINK_IS_LINKED(pa_sink_state_t x) {
- /* A generic definition for void callback functions */
- typedef void(*pa_sink_cb_t)(pa_sink *s);
-+typedef int (*pa_sink_get_mute_cb_t)(pa_sink *s, bool *mute);
-+
- struct pa_sink {
-     pa_msgobject parent;
-@@ -195,14 +197,24 @@ struct pa_sink {
-      * set this callback. */
-     pa_sink_cb_t write_volume; /* may be NULL */
--    /* Called when the mute setting is queried. A PA_SINK_MESSAGE_GET_MUTE
--     * message will also be sent. Called from IO thread if PA_SINK_DEFERRED_VOLUME
--     * flag is set otherwise from main loop context. If refresh_mute is false
--     * neither this function is called nor a message is sent.
-+    /* If the sink mute can change "spontaneously" (i.e. initiated by the sink
-+     * implementation, not by someone else calling pa_sink_set_mute()), then
-+     * the sink implementation can notify about changed mute either by calling
-+     * pa_sink_mute_changed() or by calling pa_sink_get_mute() with
-+     * force_refresh=true. If the implementation chooses the latter approach,
-+     * it should implement the get_mute callback. Otherwise get_mute can be
-+     * NULL.
-+     *
-+     * This is called when pa_sink_get_mute() is called with
-+     * force_refresh=true. This is called from the IO thread if the
-+     * PA_SINK_DEFERRED_VOLUME flag is set, otherwise this is called from the
-+     * main thread. On success, the implementation is expected to return 0 and
-+     * set the mute parameter that is passed as a reference. On failure, the
-+     * implementation is expected to return -1.
-      *
-      * You must use the function pa_sink_set_get_mute_callback() to
-      * set this callback. */
--    pa_sink_cb_t get_mute; /* may be NULL */
-+    pa_sink_get_mute_cb_t get_mute;
-     /* Called when the mute setting shall be changed. A PA_SINK_MESSAGE_SET_MUTE
-      * message will also be sent. Called from IO thread if PA_SINK_DEFERRED_VOLUME
-@@ -386,7 +398,7 @@ pa_sink* pa_sink_new(
- void pa_sink_set_get_volume_callback(pa_sink *s, pa_sink_cb_t cb);
- void pa_sink_set_set_volume_callback(pa_sink *s, pa_sink_cb_t cb);
- void pa_sink_set_write_volume_callback(pa_sink *s, pa_sink_cb_t cb);
--void pa_sink_set_get_mute_callback(pa_sink *s, pa_sink_cb_t cb);
-+void pa_sink_set_get_mute_callback(pa_sink *s, pa_sink_get_mute_cb_t cb);
- void pa_sink_set_set_mute_callback(pa_sink *s, pa_sink_cb_t cb);
- void pa_sink_enable_decibel_volume(pa_sink *s, bool enable);
-diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
-index 2f6aaad..24e8be9 100644
---- a/src/pulsecore/source.c
-+++ b/src/pulsecore/source.c
-@@ -467,7 +467,7 @@ void pa_source_set_write_volume_callback(pa_source *s, pa_source_cb_t cb) {
-         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
- }
--void pa_source_set_get_mute_callback(pa_source *s, pa_source_cb_t cb) {
-+void pa_source_set_get_mute_callback(pa_source *s, pa_source_get_mute_cb_t cb) {
-     pa_assert(s);
-     s->get_mute = cb;
-@@ -1835,21 +1835,15 @@ bool pa_source_get_mute(pa_source *s, bool force_refresh) {
-     pa_assert_ctl_context();
-     pa_assert(PA_SOURCE_IS_LINKED(s->state));
--    if (s->refresh_muted || force_refresh) {
--        bool old_muted = s->muted;
-+    if ((s->refresh_muted || force_refresh) && s->get_mute) {
-+        bool mute;
--        if (!(s->flags & PA_SOURCE_DEFERRED_VOLUME) && s->get_mute)
--            s->get_mute(s);
--
--        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
--
--        if (old_muted != s->muted) {
--            s->save_muted = true;
--
--            pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
--
--            /* Make sure the soft mute status stays in sync */
--            pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
-+        if (s->flags & PA_SOURCE_DEFERRED_VOLUME) {
-+            if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, &mute, 0, NULL) >= 0)
-+                pa_source_mute_changed(s, mute);
-+        } else {
-+            if (s->get_mute(s, &mute) >= 0)
-+                pa_source_mute_changed(s, mute);
-         }
-     }
-@@ -2136,7 +2130,7 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_
-         case PA_SOURCE_MESSAGE_GET_MUTE:
-             if (s->flags & PA_SOURCE_DEFERRED_VOLUME && s->get_mute)
--                s->get_mute(s);
-+                return s->get_mute(s, userdata);
-             return 0;
-diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
-index ca2ed59..83bc2dd 100644
---- a/src/pulsecore/source.h
-+++ b/src/pulsecore/source.h
-@@ -58,6 +58,8 @@ static inline bool PA_SOURCE_IS_LINKED(pa_source_state_t x) {
- /* A generic definition for void callback functions */
- typedef void(*pa_source_cb_t)(pa_source *s);
-+typedef int (*pa_source_get_mute_cb_t)(pa_source *s, bool *mute);
-+
- struct pa_source {
-     pa_msgobject parent;
-@@ -158,14 +160,24 @@ struct pa_source {
-      * set this callback. */
-     pa_source_cb_t write_volume; /* may be NULL */
--    /* Called when the mute setting is queried. Called from main loop
--     * context. If this is NULL a PA_SOURCE_MESSAGE_GET_MUTE message
--     * will be sent to the IO thread instead. If refresh_mute is
--     * false neither this function is called nor a message is sent.
-+    /* If the source mute can change "spontaneously" (i.e. initiated by the
-+     * source implementation, not by someone else calling
-+     * pa_source_set_mute()), then the source implementation can notify about
-+     * changed mute either by calling pa_source_mute_changed() or by calling
-+     * pa_source_get_mute() with force_refresh=true. If the implementation
-+     * chooses the latter approach, it should implement the get_mute callback.
-+     * Otherwise get_mute can be NULL.
-+     *
-+     * This is called when pa_source_get_mute() is called with
-+     * force_refresh=true. This is called from the IO thread if the
-+     * PA_SOURCE_DEFERRED_VOLUME flag is set, otherwise this is called from the
-+     * main thread. On success, the implementation is expected to return 0 and
-+     * set the mute parameter that is passed as a reference. On failure, the
-+     * implementation is expected to return -1.
-      *
-      * You must use the function pa_source_set_get_mute_callback() to
-      * set this callback. */
--    pa_source_cb_t get_mute; /* may be NULL */
-+    pa_source_get_mute_cb_t get_mute;
-     /* Called when the mute setting shall be changed. Called from main
-      * loop context. If this is NULL a PA_SOURCE_MESSAGE_SET_MUTE
-@@ -316,7 +328,7 @@ pa_source* pa_source_new(
- void pa_source_set_get_volume_callback(pa_source *s, pa_source_cb_t cb);
- void pa_source_set_set_volume_callback(pa_source *s, pa_source_cb_t cb);
- void pa_source_set_write_volume_callback(pa_source *s, pa_source_cb_t cb);
--void pa_source_set_get_mute_callback(pa_source *s, pa_source_cb_t cb);
-+void pa_source_set_get_mute_callback(pa_source *s, pa_source_get_mute_cb_t cb);
- void pa_source_set_set_mute_callback(pa_source *s, pa_source_cb_t cb);
- void pa_source_enable_decibel_volume(pa_source *s, bool enable);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0070-sink-input-source-output-Remove-redundant-get_mute-f.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0070-sink-input-source-output-Remove-redundant-get_mute-f.patch
deleted file mode 100644 (file)
index 9b25a3d..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 14 Apr 2014 15:24:31 +0300
-Subject: sink-input, source-output: Remove redundant get_mute() functions
-
-The functions just return the muted value. Callers can as well read
-the struct field directly, it's simpler that way.
-
-Change-Id: I368f7e09cdf522039a6573e5002f7544b4e840d3
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/dbus/iface-stream.c     | 4 ++--
- src/modules/module-role-cork.c      | 9 ++++-----
- src/modules/module-stream-restore.c | 4 ++--
- src/pulsecore/cli-text.c            | 4 ++--
- src/pulsecore/protocol-native.c     | 4 ++--
- src/pulsecore/sink-input.c          | 9 ---------
- src/pulsecore/sink-input.h          | 1 -
- src/pulsecore/source-output.c       | 9 ---------
- src/pulsecore/source-output.h       | 1 -
- 9 files changed, 12 insertions(+), 33 deletions(-)
-
-diff --git a/src/modules/dbus/iface-stream.c b/src/modules/dbus/iface-stream.c
-index 1cff95e..4cbcd74 100644
---- a/src/modules/dbus/iface-stream.c
-+++ b/src/modules/dbus/iface-stream.c
-@@ -765,7 +765,7 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
-             }
-         }
--        new_mute = pa_sink_input_get_mute(s->sink_input);
-+        new_mute = s->sink_input->muted;
-         if (s->mute != new_mute) {
-             s->mute = new_mute;
-@@ -861,7 +861,7 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, p
-     else
-         pa_cvolume_init(&s->volume);
--    s->mute = pa_sink_input_get_mute(sink_input);
-+    s->mute = sink_input->muted;
-     s->proplist = pa_proplist_copy(sink_input->proplist);
-     s->dbus_protocol = pa_dbus_protocol_get(sink_input->core);
-     s->subscription = pa_subscription_new(sink_input->core, PA_SUBSCRIPTION_MASK_SINK_INPUT, subscription_cb, s);
-diff --git a/src/modules/module-role-cork.c b/src/modules/module-role-cork.c
-index 6573cd6..8ca2109 100644
---- a/src/modules/module-role-cork.c
-+++ b/src/modules/module-role-cork.c
-@@ -102,7 +102,7 @@ static inline void apply_cork_to_sink(struct userdata *u, pa_sink *s, pa_sink_in
-     pa_sink_assert_ref(s);
-     for (j = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); j; j = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
--        bool corked, muted, corked_here;
-+        bool corked, corked_here;
-         const char *role;
-         if (j == ignore)
-@@ -119,10 +119,9 @@ static inline void apply_cork_to_sink(struct userdata *u, pa_sink *s, pa_sink_in
-             continue;
-         corked = (pa_sink_input_get_state(j) == PA_SINK_INPUT_CORKED);
--        muted = pa_sink_input_get_mute(j);
-         corked_here = !!pa_hashmap_get(u->cork_state, j);
--        if (cork && !corked && !muted) {
-+        if (cork && !corked && !j->muted) {
-             pa_log_debug("Found a '%s' stream that should be corked/muted.", cork_role);
-             if (!corked_here)
-                 pa_hashmap_put(u->cork_state, j, PA_INT_TO_PTR(1));
-@@ -131,9 +130,9 @@ static inline void apply_cork_to_sink(struct userdata *u, pa_sink *s, pa_sink_in
-         } else if (!cork) {
-             pa_hashmap_remove(u->cork_state, j);
--            if (corked_here && (corked || muted)) {
-+            if (corked_here && (corked || j->muted)) {
-                 pa_log_debug("Found a '%s' stream that should be uncorked/unmuted.", cork_role);
--                if (muted)
-+                if (j->muted)
-                     pa_sink_input_set_mute(j, false, false);
-                 if (corked)
-                     pa_sink_input_send_event(j, PA_STREAM_EVENT_REQUEST_UNCORK, NULL);
-diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
-index 68968c9..4fc5645 100644
---- a/src/modules/module-stream-restore.c
-+++ b/src/modules/module-stream-restore.c
-@@ -1303,7 +1303,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
-         }
-         if (sink_input->save_muted) {
--            entry->muted = pa_sink_input_get_mute(sink_input);
-+            entry->muted = sink_input->muted;
-             entry->muted_valid = true;
-             mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted);
-@@ -1353,7 +1353,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
-         }
-         if (source_output->save_muted) {
--            entry->muted = pa_source_output_get_mute(source_output);
-+            entry->muted = source_output->muted;
-             entry->muted_valid = true;
-             mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted);
-diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
-index c7db0a6..2992ae8 100644
---- a/src/pulsecore/cli-text.c
-+++ b/src/pulsecore/cli-text.c
-@@ -536,7 +536,7 @@ char *pa_source_output_list_to_string(pa_core *c) {
-             state_table[pa_source_output_get_state(o)],
-             o->source->index, o->source->name,
-             volume_str,
--            pa_yes_no(pa_source_output_get_mute(o)),
-+            pa_yes_no(o->muted),
-             (double) pa_source_output_get_latency(o, NULL) / PA_USEC_PER_MSEC,
-             clt,
-             pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec),
-@@ -634,7 +634,7 @@ char *pa_sink_input_list_to_string(pa_core *c) {
-             state_table[pa_sink_input_get_state(i)],
-             i->sink->index, i->sink->name,
-             volume_str,
--            pa_yes_no(pa_sink_input_get_mute(i)),
-+            pa_yes_no(i->muted),
-             (double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC,
-             clt,
-             pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec),
-diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
-index 4304cd4..21e02fe 100644
---- a/src/pulsecore/protocol-native.c
-+++ b/src/pulsecore/protocol-native.c
-@@ -3378,7 +3378,7 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t,
-     pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
-     pa_tagstruct_puts(t, s->driver);
-     if (c->version >= 11)
--        pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
-+        pa_tagstruct_put_boolean(t, s->muted);
-     if (c->version >= 13)
-         pa_tagstruct_put_proplist(t, s->proplist);
-     if (c->version >= 19)
-@@ -3425,7 +3425,7 @@ static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *
-         pa_tagstruct_put_boolean(t, (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_CORKED));
-     if (c->version >= 22) {
-         pa_tagstruct_put_cvolume(t, &v);
--        pa_tagstruct_put_boolean(t, pa_source_output_get_mute(s));
-+        pa_tagstruct_put_boolean(t, s->muted);
-         pa_tagstruct_put_boolean(t, has_volume);
-         pa_tagstruct_put_boolean(t, s->volume_writable);
-         pa_tagstruct_put_format_info(t, s->format);
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index f706acc..a274620 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -1485,15 +1485,6 @@ void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save) {
-     pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
- }
--/* Called from main context */
--bool pa_sink_input_get_mute(pa_sink_input *i) {
--    pa_sink_input_assert_ref(i);
--    pa_assert_ctl_context();
--    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
--
--    return i->muted;
--}
--
- /* Called from main thread */
- void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) {
-     pa_sink_input_assert_ref(i);
-diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
-index 4e7b229..1bd3eee 100644
---- a/src/pulsecore/sink-input.h
-+++ b/src/pulsecore/sink-input.h
-@@ -387,7 +387,6 @@ int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key);
- pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, bool absolute);
- void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save);
--bool pa_sink_input_get_mute(pa_sink_input *i);
- void pa_sink_input_set_volume_ramp(pa_sink_input *i, const pa_cvolume_ramp *ramp, bool send_msg, bool save);
-diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
-index bb89384..d3888df 100644
---- a/src/pulsecore/source-output.c
-+++ b/src/pulsecore/source-output.c
-@@ -1084,15 +1084,6 @@ void pa_source_output_set_mute(pa_source_output *o, bool mute, bool save) {
-     pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
- }
--/* Called from main context */
--bool pa_source_output_get_mute(pa_source_output *o) {
--    pa_source_output_assert_ref(o);
--    pa_assert_ctl_context();
--    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
--
--    return o->muted;
--}
--
- /* Called from main thread */
- void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p) {
-     pa_source_output_assert_ref(o);
-diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
-index 27d6fd4..73170d3 100644
---- a/src/pulsecore/source-output.h
-+++ b/src/pulsecore/source-output.h
-@@ -318,7 +318,6 @@ void pa_source_output_set_volume(pa_source_output *o, const pa_cvolume *volume,
- pa_cvolume *pa_source_output_get_volume(pa_source_output *o, pa_cvolume *volume, bool absolute);
- void pa_source_output_set_mute(pa_source_output *o, bool mute, bool save);
--bool pa_source_output_get_mute(pa_source_output *o);
- void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0071-solaris-tunnel-Remove-some-redundant-boolean-convers.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0071-solaris-tunnel-Remove-some-redundant-boolean-convers.patch
deleted file mode 100644 (file)
index 4b4acfe..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 14 Apr 2014 15:34:57 +0300
-Subject: solaris, tunnel: Remove some redundant boolean conversions
-
-Change-Id: Ibc922f8455a3ccb6c71289e70cd474464930643e
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/modules/module-solaris.c | 2 +-
- src/modules/module-tunnel.c  | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c
-index 71a98e9..4f11000 100644
---- a/src/modules/module-solaris.c
-+++ b/src/modules/module-solaris.c
-@@ -564,7 +564,7 @@ static void sink_set_mute(pa_sink *s) {
-     if (u->fd >= 0) {
-         AUDIO_INITINFO(&info);
--        info.output_muted = !!s->muted;
-+        info.output_muted = s->muted;
-         if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
-             pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
-diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c
-index 1ddfd25..0fc3d73 100644
---- a/src/modules/module-tunnel.c
-+++ b/src/modules/module-tunnel.c
-@@ -1906,7 +1906,7 @@ static void sink_set_mute(pa_sink *sink) {
-     pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_MUTE);
-     pa_tagstruct_putu32(t, u->ctag++);
-     pa_tagstruct_putu32(t, u->device_index);
--    pa_tagstruct_put_boolean(t, !!sink->muted);
-+    pa_tagstruct_put_boolean(t, sink->muted);
-     pa_pstream_send_tagstruct(u->pstream, t);
- }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0072-sink-source-Add-hooks-for-volume-changes.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0072-sink-source-Add-hooks-for-volume-changes.patch
deleted file mode 100644 (file)
index 08fbc83..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Sun, 9 Mar 2014 13:36:04 +0200
-Subject: sink, source: Add hooks for volume changes
-
-Change-Id: Id4389a38e601dee3f84d7fad0583a7dc87108e87
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/core.h   | 2 ++
- src/pulsecore/sink.c   | 1 +
- src/pulsecore/source.c | 1 +
- 3 files changed, 4 insertions(+)
-
-diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
-index e1cd18f..85f1b81 100644
---- a/src/pulsecore/core.h
-+++ b/src/pulsecore/core.h
-@@ -76,6 +76,7 @@ typedef enum pa_core_hook {
-     PA_CORE_HOOK_SINK_PROPLIST_CHANGED,
-     PA_CORE_HOOK_SINK_PORT_CHANGED,
-     PA_CORE_HOOK_SINK_FLAGS_CHANGED,
-+    PA_CORE_HOOK_SINK_VOLUME_CHANGED,
-     PA_CORE_HOOK_SOURCE_NEW,
-     PA_CORE_HOOK_SOURCE_FIXATE,
-     PA_CORE_HOOK_SOURCE_PUT,
-@@ -85,6 +86,7 @@ typedef enum pa_core_hook {
-     PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED,
-     PA_CORE_HOOK_SOURCE_PORT_CHANGED,
-     PA_CORE_HOOK_SOURCE_FLAGS_CHANGED,
-+    PA_CORE_HOOK_SOURCE_VOLUME_CHANGED,
-     PA_CORE_HOOK_SINK_INPUT_NEW,
-     PA_CORE_HOOK_SINK_INPUT_FIXATE,
-     PA_CORE_HOOK_SINK_INPUT_PUT,
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index b64001b..f8e5449 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -3907,4 +3907,5 @@ void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume) {
-                                             s->flags & PA_SINK_DECIBEL_VOLUME));
-     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-+    pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED], s);
- }
-diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
-index 24e8be9..8a43708 100644
---- a/src/pulsecore/source.c
-+++ b/src/pulsecore/source.c
-@@ -2900,4 +2900,5 @@ void pa_source_set_reference_volume_direct(pa_source *s, const pa_cvolume *volum
-                                             s->flags & PA_SOURCE_DECIBEL_VOLUME));
-     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-+    pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED], s);
- }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0073-sink-input-source-output-Add-hooks-for-volume-change.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0073-sink-input-source-output-Add-hooks-for-volume-change.patch
deleted file mode 100644 (file)
index 9cf1c67..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 7 Apr 2014 14:22:43 +0300
-Subject: sink-input, source-output: Add hooks for volume changes
-
-Change-Id: I89c6f2934762caa2c49c70c0446c14d0de58a10e
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/core.h          | 2 ++
- src/pulsecore/sink-input.c    | 1 +
- src/pulsecore/source-output.c | 1 +
- 3 files changed, 4 insertions(+)
-
-diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
-index 85f1b81..a839898 100644
---- a/src/pulsecore/core.h
-+++ b/src/pulsecore/core.h
-@@ -97,6 +97,7 @@ typedef enum pa_core_hook {
-     PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL,
-     PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED,
-     PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED,
-+    PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED,
-     PA_CORE_HOOK_SINK_INPUT_SEND_EVENT,
-     PA_CORE_HOOK_SOURCE_OUTPUT_NEW,
-     PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE,
-@@ -108,6 +109,7 @@ typedef enum pa_core_hook {
-     PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL,
-     PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED,
-     PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED,
-+    PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED,
-     PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT,
-     PA_CORE_HOOK_CLIENT_NEW,
-     PA_CORE_HOOK_CLIENT_PUT,
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index a274620..3024539 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -2326,4 +2326,5 @@ void pa_sink_input_set_volume_direct(pa_sink_input *i, const pa_cvolume *volume)
-         i->volume_changed(i);
-     pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
-+    pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED], i);
- }
-diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
-index d3888df..18a1478 100644
---- a/src/pulsecore/source-output.c
-+++ b/src/pulsecore/source-output.c
-@@ -1692,4 +1692,5 @@ void pa_source_output_set_volume_direct(pa_source_output *o, const pa_cvolume *v
-         o->volume_changed(o);
-     pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
-+    pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED], o);
- }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0074-sink-source-Add-hooks-for-mute-changes.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0074-sink-source-Add-hooks-for-mute-changes.patch
deleted file mode 100644 (file)
index ddd8514..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Tue, 15 Apr 2014 11:10:24 +0300
-Subject: sink, source: Add hooks for mute changes
-
-Change-Id: I1203c1199fea0e93f1a61391695b12ab8af66180
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/core.h   | 2 ++
- src/pulsecore/sink.c   | 1 +
- src/pulsecore/source.c | 1 +
- 3 files changed, 4 insertions(+)
-
-diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
-index a839898..af7fa50 100644
---- a/src/pulsecore/core.h
-+++ b/src/pulsecore/core.h
-@@ -77,6 +77,7 @@ typedef enum pa_core_hook {
-     PA_CORE_HOOK_SINK_PORT_CHANGED,
-     PA_CORE_HOOK_SINK_FLAGS_CHANGED,
-     PA_CORE_HOOK_SINK_VOLUME_CHANGED,
-+    PA_CORE_HOOK_SINK_MUTE_CHANGED,
-     PA_CORE_HOOK_SOURCE_NEW,
-     PA_CORE_HOOK_SOURCE_FIXATE,
-     PA_CORE_HOOK_SOURCE_PUT,
-@@ -87,6 +88,7 @@ typedef enum pa_core_hook {
-     PA_CORE_HOOK_SOURCE_PORT_CHANGED,
-     PA_CORE_HOOK_SOURCE_FLAGS_CHANGED,
-     PA_CORE_HOOK_SOURCE_VOLUME_CHANGED,
-+    PA_CORE_HOOK_SOURCE_MUTE_CHANGED,
-     PA_CORE_HOOK_SINK_INPUT_NEW,
-     PA_CORE_HOOK_SINK_INPUT_FIXATE,
-     PA_CORE_HOOK_SINK_INPUT_PUT,
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index f8e5449..695e471 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -2308,6 +2308,7 @@ void pa_sink_set_mute(pa_sink *s, bool mute, bool save) {
-     pa_log_debug("The mute of sink %s changed from %s to %s.", s->name, pa_yes_no(old_muted), pa_yes_no(mute));
-     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
-     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-+    pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_MUTE_CHANGED], s);
- }
- /* Called from main thread */
-diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
-index 8a43708..0fddfaa 100644
---- a/src/pulsecore/source.c
-+++ b/src/pulsecore/source.c
-@@ -1826,6 +1826,7 @@ void pa_source_set_mute(pa_source *s, bool mute, bool save) {
-     pa_log_debug("The mute of source %s changed from %s to %s.", s->name, pa_yes_no(old_muted), pa_yes_no(mute));
-     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
-     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-+    pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_MUTE_CHANGED], s);
- }
- /* Called from main thread */
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0075-sink-input-source-output-Add-hooks-for-mute-changes.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0075-sink-input-source-output-Add-hooks-for-mute-changes.patch
deleted file mode 100644 (file)
index 2607c14..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Tue, 15 Apr 2014 11:27:53 +0300
-Subject: sink-input, source-output: Add hooks for mute changes
-
-Change-Id: I256cfa27ffa6addb35640266b73f1fe07a483203
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/core.h          | 2 ++
- src/pulsecore/sink-input.c    | 1 +
- src/pulsecore/source-output.c | 1 +
- 3 files changed, 4 insertions(+)
-
-diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
-index af7fa50..1f042b9 100644
---- a/src/pulsecore/core.h
-+++ b/src/pulsecore/core.h
-@@ -100,6 +100,7 @@ typedef enum pa_core_hook {
-     PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED,
-     PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED,
-     PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED,
-+    PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED,
-     PA_CORE_HOOK_SINK_INPUT_SEND_EVENT,
-     PA_CORE_HOOK_SOURCE_OUTPUT_NEW,
-     PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE,
-@@ -112,6 +113,7 @@ typedef enum pa_core_hook {
-     PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED,
-     PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED,
-     PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED,
-+    PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED,
-     PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT,
-     PA_CORE_HOOK_CLIENT_NEW,
-     PA_CORE_HOOK_CLIENT_PUT,
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index 3024539..9d13269 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -1483,6 +1483,7 @@ void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save) {
-         i->mute_changed(i);
-     pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
-+    pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED], i);
- }
- /* Called from main thread */
-diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
-index 18a1478..d3d15f1 100644
---- a/src/pulsecore/source-output.c
-+++ b/src/pulsecore/source-output.c
-@@ -1082,6 +1082,7 @@ void pa_source_output_set_mute(pa_source_output *o, bool mute, bool save) {
-         o->mute_changed(o);
-     pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
-+    pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED], o);
- }
- /* Called from main thread */
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0076-sink-Link-monitor-source-before-activating-port.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0076-sink-Link-monitor-source-before-activating-port.patch
deleted file mode 100644 (file)
index e2de6d6..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Fri, 9 May 2014 11:25:28 +0300
-Subject: sink: Link monitor source before activating port
-
-The port activation hook callbacks may want to use the monitor source.
-
-Change-Id: I5d5c51171a78162dacb3286983cb560001e79ba1
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/pulsecore/sink.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index 695e471..191b560 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -669,11 +669,11 @@ void pa_sink_put(pa_sink* s) {
-     else
-         pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
-+    pa_source_put(s->monitor_source);
-+
-     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);
-     pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
- }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0077-context-extension-Add-the-pa_extension-class.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0077-context-extension-Add-the-pa_extension-class.patch
deleted file mode 100644 (file)
index a2a5141..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Tue, 4 Mar 2014 15:03:05 +0200
-Subject: context, extension: Add the pa_extension class
-
-pa_extension is an abstraction layer that allows pa_context to manage
-the extensions without needing any extension-specific code. This patch
-only implements the pa_extension base class, the class isn't used yet
-by any actual extensions.
-
-Change-Id: I457b3d0b674b4cfd1d38452d8f8cb51cf6b7b533
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/Makefile.am       |   1 +
- src/pulse/context.c   |  48 +++++++++++++++++++++++-
- src/pulse/extension.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++
- src/pulse/extension.h |  63 +++++++++++++++++++++++++++++++
- src/pulse/internal.h  |   6 +++
- 5 files changed, 217 insertions(+), 1 deletion(-)
- create mode 100644 src/pulse/extension.c
- create mode 100644 src/pulse/extension.h
-
-diff --git a/src/Makefile.am b/src/Makefile.am
-index fe6cc53..22b9b81 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -813,6 +813,7 @@ libpulse_la_SOURCES = \
-               pulse/def.h \
-               pulse/direction.c pulse/direction.h \
-               pulse/error.c pulse/error.h \
-+              pulse/extension.c pulse/extension.h \
-               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 \
-diff --git a/src/pulse/context.c b/src/pulse/context.c
-index b8688f2..9c9c3d9 100644
---- a/src/pulse/context.c
-+++ b/src/pulse/context.c
-@@ -186,14 +186,20 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
-         }
-     }
-+    c->extensions = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-+
-     return c;
- }
- static void context_unlink(pa_context *c) {
-+    pa_extension *extension;
-     pa_stream *s;
-     pa_assert(c);
-+    while ((extension = pa_hashmap_first(c->extensions)))
-+        pa_extension_kill(extension);
-+
-     s = c->streams ? pa_stream_ref(c->streams) : NULL;
-     while (s) {
-         pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
-@@ -280,6 +286,9 @@ void pa_context_unref(pa_context *c) {
- }
- void pa_context_set_state(pa_context *c, pa_context_state_t st) {
-+    pa_extension *extension;
-+    void *state;
-+
-     pa_assert(c);
-     pa_assert(PA_REFCNT_VALUE(c) >= 1);
-@@ -290,6 +299,12 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) {
-     c->state = st;
-+    PA_HASHMAP_FOREACH(extension, c->extensions, state)
-+        pa_extension_context_state_changed(extension, 1);
-+
-+    PA_HASHMAP_FOREACH(extension, c->extensions, state)
-+        pa_extension_context_state_changed(extension, 2);
-+
-     if (c->state_callback)
-         c->state_callback(c, c->state_userdata);
-@@ -1338,6 +1353,7 @@ void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_t
-     pa_context *c = userdata;
-     uint32_t idx;
-     const char *name;
-+    pa_extension *extension;
-     pa_assert(pd);
-     pa_assert(command == PA_COMMAND_EXTENSION);
-@@ -1366,7 +1382,16 @@ void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_t
-         pa_ext_stream_restore_command(c, tag, t);
-     else if (pa_streq(name, "module-node-manager"))
-         pa_ext_node_manager_command(c, tag, t);
--    else
-+    else if ((extension = pa_context_get_extension(c, name))) {
-+        uint32_t subcommand;
-+
-+        if (pa_tagstruct_getu32(t, &subcommand) < 0) {
-+            pa_context_fail(c, PA_ERR_PROTOCOL);
-+            goto finish;
-+        }
-+
-+        pa_extension_process_command(extension, subcommand, tag, t);
-+    } else
-         pa_log(_("Received message for unknown extension '%s'"), name);
- finish:
-@@ -1464,3 +1489,24 @@ int pa_context_load_cookie_from_file(pa_context *c, const char *cookie_file_path
-     return pa_client_conf_load_cookie_from_file(c->conf, cookie_file_path);
- }
-+
-+pa_extension *pa_context_get_extension(pa_context *context, const char *name) {
-+    pa_assert(context);
-+    pa_assert(name);
-+
-+    return pa_hashmap_get(context->extensions, name);
-+}
-+
-+void pa_context_add_extension(pa_context *context, pa_extension *extension) {
-+    pa_assert(context);
-+    pa_assert(extension);
-+
-+    pa_assert_se(pa_hashmap_put(context->extensions, extension->name, extension) >= 0);
-+}
-+
-+int pa_context_remove_extension(pa_context *context, pa_extension *extension) {
-+    pa_assert(context);
-+    pa_assert(extension);
-+
-+    return pa_hashmap_remove(context->extensions, extension->name) ? 0 : -1;
-+}
-diff --git a/src/pulse/extension.c b/src/pulse/extension.c
-new file mode 100644
-index 0000000..17e7e6c
---- /dev/null
-+++ b/src/pulse/extension.c
-@@ -0,0 +1,100 @@
-+/***
-+  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 "extension.h"
-+
-+#include <pulsecore/macro.h>
-+
-+#include <pulse/internal.h>
-+#include <pulse/xmalloc.h>
-+
-+pa_extension *pa_extension_new(pa_context *context, const char *name) {
-+    pa_extension *extension = NULL;
-+
-+    pa_assert(context);
-+    pa_assert(name);
-+
-+    extension = pa_xnew0(pa_extension, 1);
-+    extension->context = context;
-+    extension->name = pa_xstrdup(name);
-+
-+    return extension;
-+}
-+
-+void pa_extension_put(pa_extension *extension) {
-+    pa_assert(extension);
-+    pa_assert(extension->kill);
-+
-+    pa_context_add_extension(extension->context, extension);
-+}
-+
-+static void extension_unlink(pa_extension *extension) {
-+    pa_assert(extension);
-+
-+    if (extension->unlinked)
-+        return;
-+
-+    extension->unlinked = true;
-+
-+    pa_context_remove_extension(extension->context, extension);
-+}
-+
-+void pa_extension_free(pa_extension *extension) {
-+    pa_assert(extension);
-+
-+    extension_unlink(extension);
-+
-+    pa_xfree(extension->name);
-+    pa_xfree(extension);
-+}
-+
-+void pa_extension_context_state_changed(pa_extension *extension, unsigned phase) {
-+    pa_assert(extension);
-+    pa_assert(phase == 1 || phase == 2);
-+
-+    if (extension->context_state_changed)
-+        extension->context_state_changed(extension, phase);
-+}
-+
-+void pa_extension_kill(pa_extension *extension) {
-+    pa_assert(extension);
-+
-+    if (extension->unlinked)
-+        return;
-+
-+    extension->kill(extension);
-+}
-+
-+void pa_extension_process_command(pa_extension *extension, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct) {
-+    pa_assert(extension);
-+    pa_assert(tagstruct);
-+
-+    if (extension->process_command)
-+        extension->process_command(extension, command, tag, tagstruct);
-+    else {
-+        pa_log("Unexpected command for extension %s: %u", extension->name, command);
-+        pa_context_fail(extension->context, PA_ERR_PROTOCOL);
-+    }
-+}
-diff --git a/src/pulse/extension.h b/src/pulse/extension.h
-new file mode 100644
-index 0000000..cadc267
---- /dev/null
-+++ b/src/pulse/extension.h
-@@ -0,0 +1,63 @@
-+#ifndef fooextensionhfoo
-+#define fooextensionhfoo
-+
-+/***
-+  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/context.h>
-+
-+#include <pulsecore/tagstruct.h>
-+
-+#include <stdbool.h>
-+
-+typedef struct pa_extension pa_extension;
-+
-+struct pa_extension {
-+    pa_context *context;
-+    char *name;
-+    bool unlinked;
-+
-+    /* This is called when the context state changes. The callback is called
-+     * twice for each state change, first with phase = 1 and then with
-+     * phase = 2. In the first phase the extension should update its internal
-+     * state without calling any application callbacks. In the second phase it
-+     * should call the application callbacks (if any). May be NULL. */
-+    void (*context_state_changed)(pa_extension *extension, unsigned phase);
-+
-+    /* Called from pa_extension_kill(). May not be NULL. */
-+    void (*kill)(pa_extension *extension);
-+
-+    /* Called from pa_extension_process_command(). May be NULL, if the
-+     * extension doesn't expect any commands from the server. */
-+    void (*process_command)(pa_extension *extension, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct);
-+
-+    void *userdata;
-+};
-+
-+pa_extension *pa_extension_new(pa_context *context, const char *name);
-+void pa_extension_put(pa_extension *extension);
-+void pa_extension_free(pa_extension *extension);
-+
-+void pa_extension_context_state_changed(pa_extension *extension, unsigned phase);
-+void pa_extension_kill(pa_extension *extension);
-+void pa_extension_process_command(pa_extension *extension, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct);
-+
-+#endif
-diff --git a/src/pulse/internal.h b/src/pulse/internal.h
-index 61095d0..1428fb8 100644
---- a/src/pulse/internal.h
-+++ b/src/pulse/internal.h
-@@ -23,6 +23,7 @@
-   USA.
- ***/
-+#include <pulse/extension.h>
- #include <pulse/mainloop-api.h>
- #include <pulse/context.h>
- #include <pulse/stream.h>
-@@ -103,6 +104,8 @@ struct pa_context {
-     uint32_t client_index;
-+    pa_hashmap *extensions; /* extension name -> pa_extension */
-+
-     /* Extension specific data */
-     struct {
-         pa_ext_device_manager_subscribe_cb_t callback;
-@@ -269,6 +272,9 @@ int pa_context_set_error(pa_context *c, int error);
- void pa_context_set_state(pa_context *c, pa_context_state_t st);
- int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t, bool fail);
- pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata);
-+pa_extension *pa_context_get_extension(pa_context *context, const char *name);
-+void pa_context_add_extension(pa_context *context, pa_extension *extension);
-+int pa_context_remove_extension(pa_context *context, pa_extension *extension);
- void pa_stream_set_state(pa_stream *s, pa_stream_state_t st);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0078-volume-api-Add-libvolume-api.so.patch.gz b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0078-volume-api-Add-libvolume-api.so.patch.gz
deleted file mode 100644 (file)
index 465ef38..0000000
Binary files a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0078-volume-api-Add-libvolume-api.so.patch.gz and /dev/null differ
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0079-Add-module-volume-api-and-the-related-client-API.patch.gz b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0079-Add-module-volume-api-and-the-related-client-API.patch.gz
deleted file mode 100644 (file)
index d3e3ee7..0000000
Binary files a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0079-Add-module-volume-api-and-the-related-client-API.patch.gz and /dev/null differ
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0080-pactl-Add-support-for-the-new-volume-API.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0080-pactl-Add-support-for-the-new-volume-API.patch
deleted file mode 100644 (file)
index 3fd8311..0000000
+++ /dev/null
@@ -1,963 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 21 May 2014 14:05:47 +0300
-Subject: pactl: Add support for the new volume API
-
-Change-Id: I2bb6625c1cd575366388ec8dc3dd4fd2097c9a4a
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- man/pactl.1.xml.in |  50 +++-
- src/utils/pactl.c  | 727 +++++++++++++++++++++++++++++++++++++++++++++++++++--
- 2 files changed, 759 insertions(+), 18 deletions(-)
-
-diff --git a/man/pactl.1.xml.in b/man/pactl.1.xml.in
-index 29071b3..cd54e4c 100644
---- a/man/pactl.1.xml.in
-+++ b/man/pactl.1.xml.in
-@@ -80,9 +80,12 @@ USA.
-     <option>
-       <p><opt>list</opt> [<arg>short</arg>] [<arg>TYPE</arg>]</p>
--      <optdesc><p>Dump all currently loaded modules, available sinks, sources, streams, etc.  <arg>TYPE</arg> must be one of:
--      modules, sinks, sources, sink-inputs, source-outputs, clients, samples, cards.  If not specified, all info is listed.  If
--      short is given, output is in a tabular format, for easy parsing by scripts.</p></optdesc>
-+      <optdesc><p>Dump all currently loaded modules, available sinks, sources,
-+      streams, etc.  <arg>TYPE</arg> must be one of: modules, sinks, sources,
-+      sink-inputs, source-outputs, clients, samples, cards, volume-controls,
-+      mute-controls, devices, streams, audio-groups. If not specified, all info
-+      is listed. If short is given, output is in a tabular format, for easy
-+      parsing by scripts. </p></optdesc>
-     </option>
-     <option>
-@@ -244,7 +247,46 @@ USA.
-       <arg>FORMATS</arg> is specified as a semi-colon (;) separated list of formats in the form
-       'encoding[, key1=value1, key2=value2, ...]' (for example, AC3 at 32000, 44100 and 48000 Hz would be specified as
-       'ac3-iec61937, format.rate = "[ 32000, 44100, 48000 ]"').
--      </p></optdesc> </option>
-+      </p></optdesc>
-+    </option>
-+
-+    <option>
-+      <p><opt>set-volume-control-volume</opt> <arg>CONTROL</arg>
-+        <arg>VOLUME</arg> <arg>[BALANCE ...]</arg>
-+      </p>
-+      <optdesc><p>Set the overall volume of the specified volume control
-+        (identified by its name or index). <arg>VOLUME</arg> can be specified
-+        as an integer (e.g. 2000, 16384), a linear factor (e.g. 0.4, 1.100), a
-+        percentage (e.g.  10%, 100%) or a decibel value (e.g. 0dB, 20dB).  If
-+        the volume specification start with a + or - the volume adjustment will
-+        be relative to the current source output volume. Optionally, you can
-+        also provide the channel balance (see also set-volume-control-balance).
-+      </p></optdesc>
-+    </option>
-+
-+    <option>
-+      <p><opt>set-volume-control-balance</opt> <arg>CONTROL</arg>
-+        <arg>BALANCE ...</arg>
-+      </p>
-+      <optdesc><p>Set the channel balance of the specified volume control
-+        (identified by its name or index). The balance is given as separate
-+        values for each channel. The balance values must be between 0.0 and
-+        1.0. The number of values must match the volume control's channel map.
-+      </p></optdesc>
-+    </option>
-+
-+    <option>
-+      <p>
-+        <opt>set-mute-control-mute</opt> <arg>CONTROL</arg> <arg>1|0|toggle
-+        </arg>
-+      </p>
-+      <optdesc><p>
-+        Set the mute state of the specified mute control (identified by its
-+        name or index). If the mute value is "toggle", then the mute control
-+        will be muted if it was previously unmuted, and unmuted if it was
-+        previously muted.
-+      </p></optdesc>
-+    </option>
-     <option>
-       <p><opt>subscribe</opt></p>
-diff --git a/src/utils/pactl.c b/src/utils/pactl.c
-index 958d700..f947681 100644
---- a/src/utils/pactl.c
-+++ b/src/utils/pactl.c
-@@ -39,6 +39,7 @@
- #include <pulse/pulseaudio.h>
- #include <pulse/ext-device-restore.h>
- #include <pulse/ext-node-manager.h>
-+#include <pulse/ext-volume-api.h>
- #include <pulsecore/i18n.h>
- #include <pulsecore/macro.h>
-@@ -59,7 +60,9 @@ static char
-     *card_name = NULL,
-     *profile_name = NULL,
-     *port_name = NULL,
--    *formats = NULL;
-+    *formats = NULL,
-+    *volume_control_name = NULL,
-+    *mute_control_name = NULL;
- static uint32_t
-     sink_input_idx = PA_INVALID_INDEX,
-@@ -101,6 +104,14 @@ static bool nl = false;
- static uint32_t src_node_id;
- static uint32_t dst_node_id;
- static uint32_t conn_id;
-+bool volume_api_connected = false;
-+pa_ext_volume_api_bvolume bvolume;
-+bool volume_valid = false;
-+bool balance_valid = false;
-+uint32_t main_output_volume_control = PA_INVALID_INDEX;
-+uint32_t main_input_volume_control = PA_INVALID_INDEX;
-+uint32_t main_output_mute_control = PA_INVALID_INDEX;
-+uint32_t main_input_mute_control = PA_INVALID_INDEX;
- static enum {
-     NONE,
-@@ -132,6 +143,8 @@ static enum {
-     SET_SOURCE_OUTPUT_MUTE,
-     SET_SINK_FORMATS,
-     SET_PORT_LATENCY_OFFSET,
-+    SET_VOLUME_CONTROL_VOLUME,
-+    SET_MUTE_CONTROL_MUTE,
-     SUBSCRIBE,
-     NODE_CONNECT,
-     NODE_DISCONNECT
-@@ -838,18 +851,18 @@ static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
-     complete_action();
- }
--static void volume_relative_adjust(pa_cvolume *cv) {
-+static void volume_relative_adjust(pa_cvolume *cv, pa_volume_t adjustment) {
-     pa_assert((volume_flags & VOL_RELATIVE) == VOL_RELATIVE);
-     /* Relative volume change is additive in case of UINT or PERCENT
-      * and multiplicative for LINEAR or DECIBEL */
-     if ((volume_flags & 0x0F) == VOL_UINT || (volume_flags & 0x0F) == VOL_PERCENT) {
-         pa_volume_t v = pa_cvolume_avg(cv);
--        v = v + volume < PA_VOLUME_NORM ? PA_VOLUME_MUTED : v + volume - PA_VOLUME_NORM;
-+        v = v + adjustment < PA_VOLUME_NORM ? PA_VOLUME_MUTED : v + adjustment - PA_VOLUME_NORM;
-         pa_cvolume_set(cv, 1, v);
-     }
-     if ((volume_flags & 0x0F) == VOL_LINEAR || (volume_flags & 0x0F) == VOL_DECIBEL) {
--        pa_sw_cvolume_multiply_scalar(cv, cv, volume);
-+        pa_sw_cvolume_multiply_scalar(cv, cv, adjustment);
-     }
- }
-@@ -893,7 +906,7 @@ static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int i
-     pa_assert(i);
-     cv = i->volume;
--    volume_relative_adjust(&cv);
-+    volume_relative_adjust(&cv, volume);
-     pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL));
- }
-@@ -912,7 +925,7 @@ static void get_source_volume_callback(pa_context *c, const pa_source_info *i, i
-     pa_assert(i);
-     cv = i->volume;
--    volume_relative_adjust(&cv);
-+    volume_relative_adjust(&cv, volume);
-     pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL));
- }
-@@ -931,7 +944,7 @@ static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_in
-     pa_assert(i);
-     cv = i->volume;
--    volume_relative_adjust(&cv);
-+    volume_relative_adjust(&cv, volume);
-     pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &cv, simple_callback, NULL));
- }
-@@ -950,7 +963,7 @@ static void get_source_output_volume_callback(pa_context *c, const pa_source_out
-     pa_assert(o);
-     cv = o->volume;
--    volume_relative_adjust(&cv);
-+    volume_relative_adjust(&cv, volume);
-     pa_operation_unref(pa_context_set_source_output_volume(c, source_output_idx, &cv, simple_callback, NULL));
- }
-@@ -1189,6 +1202,575 @@ static void context_subscribe_callback(pa_context *c, pa_subscription_event_type
-     fflush(stdout);
- }
-+static void get_volume_control_info_callback(pa_context *c, const pa_ext_volume_api_volume_control_info *info,
-+                                             int is_last, void *userdata) {
-+    char volume_str[PA_VOLUME_SNPRINT_VERBOSE_MAX];
-+    char balance_str[PA_EXT_VOLUME_API_BVOLUME_SNPRINT_BALANCE_MAX];
-+    char *proplist_str;
-+
-+    pa_assert(c);
-+
-+    if (is_last < 0) {
-+        pa_log(_("Failed to get volume control information: %s"), pa_strerror(pa_context_errno(c)));
-+        quit(1);
-+        return;
-+    }
-+
-+    if (is_last) {
-+        complete_action();
-+        return;
-+    }
-+
-+    pa_assert(info);
-+
-+    if (action == INFO) {
-+        if (info->index == main_output_volume_control)
-+            printf(_("Main output volume control: %s\n"), info->name);
-+
-+        if (info->index == main_input_volume_control)
-+            printf(_("Main input volume control: %s\n"), info->name);
-+
-+        return;
-+    }
-+
-+    if (action == SET_VOLUME_CONTROL_VOLUME) {
-+        pa_ext_volume_api_bvolume bv;
-+
-+        if (balance_valid && bvolume.channel_map.channels != info->volume.channel_map.channels) {
-+            pa_log(_("Incompatible number of channels, expected %u channels."), info->volume.channel_map.channels);
-+            quit(1);
-+        }
-+
-+        bv = info->volume;
-+
-+        if (volume_valid) {
-+            if (volume_flags & VOL_RELATIVE) {
-+                pa_cvolume cv;
-+
-+                pa_cvolume_set(&cv, 1, info->volume.volume);
-+                volume_relative_adjust(&cv, bvolume.volume);
-+                bv.volume = cv.values[0];
-+            } else
-+                bv.volume = bvolume.volume;
-+        }
-+
-+        if (balance_valid)
-+            memcpy(bv.balance, bvolume.balance, sizeof(bv.balance));
-+
-+        pa_operation_unref(pa_ext_volume_api_set_volume_control_volume_by_name(c, volume_control_name, &bv,
-+                                                                               volume_valid, balance_valid,
-+                                                                               simple_callback, NULL));
-+        actions++;
-+
-+        return;
-+    }
-+
-+    pa_assert(action == LIST);
-+
-+    if (nl && !short_list_format)
-+        printf("\n");
-+    nl = true;
-+
-+    if (short_list_format) {
-+        printf("%u\t%s\t%u\n", info->index, info->name, info->volume.volume);
-+        return;
-+    }
-+
-+    pa_volume_snprint_verbose(volume_str, sizeof(volume_str), info->volume.volume, info->convertible_to_dB);
-+    pa_ext_volume_api_bvolume_snprint_balance(balance_str, sizeof(balance_str), &info->volume);
-+    proplist_str = pa_proplist_to_string_sep(info->proplist, "\n\t\t");
-+
-+    printf(_("Volume Control #%u\n"
-+             "\tName: %s\n"
-+             "\tDescription: %s\n"
-+             "\tVolume: %s\n"
-+             "\tBalance: %s\n"
-+             "\tProperties: %s%s\n"),
-+             info->index,
-+             info->name,
-+             info->description,
-+             volume_str,
-+             balance_str,
-+             *proplist_str ? "\n\t\t" : _("(none)"),
-+             proplist_str);
-+
-+    pa_xfree(proplist_str);
-+}
-+
-+static void get_mute_control_info_callback(pa_context *c, const pa_ext_volume_api_mute_control_info *info, int is_last,
-+                                           void *userdata) {
-+    char *proplist_str;
-+
-+    pa_assert(c);
-+
-+    if (is_last < 0) {
-+        pa_log(_("Failed to get mute control information: %s"), pa_strerror(pa_context_errno(c)));
-+        quit(1);
-+        return;
-+    }
-+
-+    if (is_last) {
-+        complete_action();
-+        return;
-+    }
-+
-+    pa_assert(info);
-+
-+    if (action == INFO) {
-+        if (info->index == main_output_mute_control)
-+            printf(_("Main output mute control: %s\n"), info->name);
-+
-+        if (info->index == main_input_mute_control)
-+            printf(_("Main input mute control: %s\n"), info->name);
-+
-+        return;
-+    }
-+
-+    if (action == SET_MUTE_CONTROL_MUTE) {
-+        pa_operation_unref(pa_ext_volume_api_set_mute_control_mute_by_index(c, info->index, info->mute ? false : true,
-+                                                                                   simple_callback, NULL));
-+        actions++;
-+        return;
-+    }
-+
-+    pa_assert(action == LIST);
-+
-+    if (nl && !short_list_format)
-+        printf("\n");
-+    nl = true;
-+
-+    if (short_list_format) {
-+        printf("%u\t%s\t%s\n", info->index, info->name, pa_yes_no(info->mute));
-+        return;
-+    }
-+
-+    proplist_str = pa_proplist_to_string_sep(info->proplist, "\n\t\t");
-+
-+    printf(_("Mute Control #%u\n"
-+             "\tName: %s\n"
-+             "\tDescription: %s\n"
-+             "\tMute: %s\n"
-+             "\tProperties: %s%s\n"),
-+             info->index,
-+             info->name,
-+             info->description,
-+             pa_yes_no(info->mute),
-+             *proplist_str ? "\n\t\t" : _("(none)"),
-+             proplist_str);
-+
-+    pa_xfree(proplist_str);
-+}
-+
-+static void volume_api_get_server_info_callback(pa_context *c, const pa_ext_volume_api_server_info *info, void *userdata) {
-+    pa_assert(c);
-+
-+    if (!info) {
-+        pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c)));
-+        quit(1);
-+        return;
-+    }
-+
-+    main_output_volume_control = info->main_output_volume_control;
-+    main_input_volume_control = info->main_input_volume_control;
-+    main_output_mute_control = info->main_output_mute_control;
-+    main_input_mute_control = info->main_input_mute_control;
-+
-+    if (main_output_volume_control == PA_INVALID_INDEX)
-+        printf(_("Main output volume control: (unset)\n"));
-+
-+    if (main_input_volume_control == PA_INVALID_INDEX)
-+        printf(_("Main input volume control: (unset)\n"));
-+
-+    if (main_output_mute_control == PA_INVALID_INDEX)
-+        printf(_("Main output mute control: (unset)\n"));
-+
-+    if (main_input_mute_control == PA_INVALID_INDEX)
-+        printf(_("Main input mute control: (unset)\n"));
-+
-+    if (main_output_volume_control != PA_INVALID_INDEX || main_input_volume_control != PA_INVALID_INDEX) {
-+        pa_operation_unref(pa_ext_volume_api_get_volume_control_info_list(c, get_volume_control_info_callback, NULL));
-+        actions++;
-+    }
-+
-+    if (main_output_mute_control != PA_INVALID_INDEX || main_input_mute_control != PA_INVALID_INDEX) {
-+        pa_operation_unref(pa_ext_volume_api_get_mute_control_info_list(c, get_mute_control_info_callback, NULL));
-+        actions++;
-+    }
-+
-+    complete_action();
-+}
-+
-+static void get_device_info_callback(pa_context *c, const pa_ext_volume_api_device_info *info, int is_last,
-+                                     void *userdata) {
-+    char *device_types_str = NULL;
-+    char *volume_control_str;
-+    char *mute_control_str;
-+    char *proplist_str;
-+
-+    pa_assert(c);
-+
-+    if (is_last < 0) {
-+        pa_log(_("Failed to get device information: %s"), pa_strerror(pa_context_errno(c)));
-+        quit(1);
-+        return;
-+    }
-+
-+    if (is_last) {
-+        complete_action();
-+        return;
-+    }
-+
-+    pa_assert(info);
-+
-+    if (nl && !short_list_format)
-+        printf("\n");
-+    nl = true;
-+
-+    if (info->n_device_types > 0)
-+        device_types_str = pa_join(info->device_types, info->n_device_types, ", ");
-+    else
-+        device_types_str = pa_xstrdup(_("(none)"));
-+
-+    if (info->volume_control != PA_INVALID_INDEX)
-+        volume_control_str = pa_sprintf_malloc("%u", info->volume_control);
-+    else
-+        volume_control_str = pa_xstrdup(_("(unset)"));
-+
-+    if (info->mute_control != PA_INVALID_INDEX)
-+        mute_control_str = pa_sprintf_malloc("%u", info->mute_control);
-+    else
-+        mute_control_str = pa_xstrdup(_("(unset)"));
-+
-+    if (short_list_format) {
-+        printf("%u\t%s\t%s\t%s\t%s\t%s\n", info->index, info->name, pa_direction_to_string(info->direction), device_types_str,
-+               volume_control_str, mute_control_str);
-+        pa_xfree(mute_control_str);
-+        pa_xfree(volume_control_str);
-+        pa_xfree(device_types_str);
-+        return;
-+    }
-+
-+    proplist_str = pa_proplist_to_string_sep(info->proplist, "\n\t\t");
-+
-+    printf(_("Device #%u\n"
-+             "\tName: %s\n"
-+             "\tDescription: %s\n"
-+             "\tDirection: %s\n"
-+             "\tDevice Types: %s\n"
-+             "\tVolume Control: %s\n"
-+             "\tMute Control: %s\n"
-+             "\tProperties: %s%s\n"),
-+             info->index,
-+             info->name,
-+             info->description,
-+             pa_direction_to_string(info->direction),
-+             device_types_str,
-+             volume_control_str,
-+             mute_control_str,
-+             *proplist_str ? "\n\t\t" : _("(none)"),
-+             proplist_str);
-+
-+    pa_xfree(proplist_str);
-+    pa_xfree(mute_control_str);
-+    pa_xfree(volume_control_str);
-+    pa_xfree(device_types_str);
-+}
-+
-+static void get_stream_info_callback(pa_context *c, const pa_ext_volume_api_stream_info *info, int is_last,
-+                                     void *userdata) {
-+    char *volume_control_str;
-+    char *mute_control_str;
-+    char *proplist_str;
-+
-+    pa_assert(c);
-+
-+    if (is_last < 0) {
-+        pa_log(_("Failed to get stream information: %s"), pa_strerror(pa_context_errno(c)));
-+        quit(1);
-+        return;
-+    }
-+
-+    if (is_last) {
-+        complete_action();
-+        return;
-+    }
-+
-+    pa_assert(info);
-+
-+    if (nl && !short_list_format)
-+        printf("\n");
-+    nl = true;
-+
-+    if (info->volume_control != PA_INVALID_INDEX)
-+        volume_control_str = pa_sprintf_malloc("%u", info->volume_control);
-+    else
-+        volume_control_str = pa_xstrdup(_("(unset)"));
-+
-+    if (info->mute_control != PA_INVALID_INDEX)
-+        mute_control_str = pa_sprintf_malloc("%u", info->mute_control);
-+    else
-+        mute_control_str = pa_xstrdup(_("(unset)"));
-+
-+    if (short_list_format) {
-+        printf("%u\t%s\t%s\t%s\t%s\n", info->index, info->name, pa_direction_to_string(info->direction), volume_control_str,
-+               mute_control_str);
-+        pa_xfree(mute_control_str);
-+        pa_xfree(volume_control_str);
-+        return;
-+    }
-+
-+    proplist_str = pa_proplist_to_string_sep(info->proplist, "\n\t\t");
-+
-+    printf(_("Stream #%u\n"
-+             "\tName: %s\n"
-+             "\tDescription: %s\n"
-+             "\tDirection: %s\n"
-+             "\tVolume Control: %s\n"
-+             "\tMute Control: %s\n"
-+             "\tProperties: %s%s\n"),
-+             info->index,
-+             info->name,
-+             info->description,
-+             pa_direction_to_string(info->direction),
-+             volume_control_str,
-+             mute_control_str,
-+             *proplist_str ? "\n\t\t" : _("(none)"),
-+             proplist_str);
-+
-+    pa_xfree(proplist_str);
-+    pa_xfree(mute_control_str);
-+    pa_xfree(volume_control_str);
-+}
-+
-+static void get_audio_group_info_callback(pa_context *c, const pa_ext_volume_api_audio_group_info *info, int is_last,
-+                                          void *userdata) {
-+    char *volume_control_str;
-+    char *mute_control_str;
-+    char *proplist_str;
-+
-+    pa_assert(c);
-+
-+    if (is_last < 0) {
-+        pa_log(_("Failed to get audio group information: %s"), pa_strerror(pa_context_errno(c)));
-+        quit(1);
-+        return;
-+    }
-+
-+    if (is_last) {
-+        complete_action();
-+        return;
-+    }
-+
-+    pa_assert(info);
-+
-+    if (nl && !short_list_format)
-+        printf("\n");
-+    nl = true;
-+
-+    if (info->volume_control != PA_INVALID_INDEX)
-+        volume_control_str = pa_sprintf_malloc("%u", info->volume_control);
-+    else
-+        volume_control_str = pa_xstrdup(_("(unset)"));
-+
-+    if (info->mute_control != PA_INVALID_INDEX)
-+        mute_control_str = pa_sprintf_malloc("%u", info->mute_control);
-+    else
-+        mute_control_str = pa_xstrdup(_("(unset)"));
-+
-+    if (short_list_format) {
-+        printf("%u\t%s\t%s\t%s\n", info->index, info->name, volume_control_str, mute_control_str);
-+        pa_xfree(mute_control_str);
-+        pa_xfree(volume_control_str);
-+        return;
-+    }
-+
-+    proplist_str = pa_proplist_to_string_sep(info->proplist, "\n\t\t");
-+
-+    printf(_("Audio Group #%u\n"
-+             "\tName: %s\n"
-+             "\tDescription: %s\n"
-+             "\tVolume Control: %s\n"
-+             "\tMute Control: %s\n"
-+             "\tProperties: %s%s\n"),
-+             info->index,
-+             info->name,
-+             info->description,
-+             volume_control_str,
-+             mute_control_str,
-+             *proplist_str ? "\n\t\t" : _("(none)"),
-+             proplist_str);
-+
-+    pa_xfree(proplist_str);
-+    pa_xfree(mute_control_str);
-+    pa_xfree(volume_control_str);
-+}
-+
-+static const char *volume_api_subscription_event_facility_to_string(pa_ext_volume_api_subscription_event_type_t type) {
-+
-+    switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
-+        case PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_SERVER:
-+            return _("server (volume API)");
-+
-+        case PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_VOLUME_CONTROL:
-+            return _("volume-control");
-+
-+        case PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_MUTE_CONTROL:
-+            return _("mute-control");
-+
-+        case PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_DEVICE:
-+            return _("device");
-+
-+        case PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_STREAM:
-+            return _("stream");
-+
-+        case PA_EXT_VOLUME_API_SUBSCRIPTION_EVENT_AUDIO_GROUP:
-+            return _("audio-group");
-+    }
-+
-+    return _("unknown");
-+}
-+
-+static void volume_api_subscribe_cb(pa_context *c, pa_ext_volume_api_subscription_event_type_t event_type, uint32_t idx,
-+                                    void *userdata) {
-+    pa_assert(c);
-+
-+    printf(_("Event '%s' on %s #%u\n"),
-+           subscription_event_type_to_string(event_type),
-+           volume_api_subscription_event_facility_to_string(event_type),
-+           idx);
-+    fflush(stdout);
-+}
-+
-+static void volume_api_state_cb(pa_context *c, void *userdata) {
-+    pa_ext_volume_api_state_t state;
-+
-+    pa_assert(c);
-+
-+    state = pa_ext_volume_api_get_state(c);
-+
-+    switch (state) {
-+        case PA_EXT_VOLUME_API_STATE_READY: {
-+            pa_operation *o = NULL;
-+
-+            volume_api_connected = true;
-+
-+            switch (action) {
-+                case INFO:
-+                    o = pa_ext_volume_api_get_server_info(c, volume_api_get_server_info_callback, NULL);
-+                    actions++;
-+                    break;
-+
-+                case LIST:
-+                    if (!list_type) {
-+                        o = pa_ext_volume_api_get_volume_control_info_list(c, get_volume_control_info_callback, NULL);
-+                        pa_operation_unref(o);
-+                        o = pa_ext_volume_api_get_mute_control_info_list(c, get_mute_control_info_callback, NULL);
-+                        pa_operation_unref(o);
-+                        o = pa_ext_volume_api_get_device_info_list(c, get_device_info_callback, NULL);
-+                        pa_operation_unref(o);
-+                        o = pa_ext_volume_api_get_stream_info_list(c, get_stream_info_callback, NULL);
-+                        pa_operation_unref(o);
-+                        o = pa_ext_volume_api_get_audio_group_info_list(c, get_audio_group_info_callback, NULL);
-+                        pa_operation_unref(o);
-+                        o = NULL;
-+                        actions += 4;
-+                    } else if (pa_streq(list_type, "volume-controls")) {
-+                        o = pa_ext_volume_api_get_volume_control_info_list(c, get_volume_control_info_callback, NULL);
-+                        actions++;
-+                    } else if (pa_streq(list_type, "mute-controls")) {
-+                        o = pa_ext_volume_api_get_mute_control_info_list(c, get_mute_control_info_callback, NULL);
-+                        actions++;
-+                    } else if (pa_streq(list_type, "devices")) {
-+                        o = pa_ext_volume_api_get_device_info_list(c, get_device_info_callback, NULL);
-+                        actions++;
-+                    } else if (pa_streq(list_type, "streams")) {
-+                        o = pa_ext_volume_api_get_stream_info_list(c, get_stream_info_callback, NULL);
-+                        actions++;
-+                    } else if (pa_streq(list_type, "audio-groups")) {
-+                        o = pa_ext_volume_api_get_audio_group_info_list(c, get_audio_group_info_callback, NULL);
-+                        actions++;
-+                    }
-+                    break;
-+
-+                case SET_VOLUME_CONTROL_VOLUME:
-+                    if (!balance_valid && !(volume_flags & VOL_RELATIVE)) {
-+                        pa_assert(volume_valid);
-+                        o = pa_ext_volume_api_set_volume_control_volume_by_name(c, volume_control_name, &bvolume, true,
-+                                                                                false, simple_callback, NULL);
-+                    } else
-+                        o = pa_ext_volume_api_get_volume_control_info_by_name(c, volume_control_name,
-+                                                                              get_volume_control_info_callback, NULL);
-+
-+                    actions++;
-+                    break;
-+
-+                case SET_MUTE_CONTROL_MUTE:
-+                    if (mute == TOGGLE_MUTE)
-+                        o = pa_ext_volume_api_get_mute_control_info_by_name(c, mute_control_name,
-+                                                                                  get_mute_control_info_callback, NULL);
-+                    else
-+                        o = pa_ext_volume_api_set_mute_control_mute_by_name(c, mute_control_name, mute, simple_callback,
-+                                                                            NULL);
-+
-+                    actions++;
-+                    break;
-+
-+                case SUBSCRIBE:
-+                    pa_ext_volume_api_set_subscribe_callback(c, volume_api_subscribe_cb, NULL);
-+                    o = pa_ext_volume_api_subscribe(c, PA_EXT_VOLUME_API_SUBSCRIPTION_MASK_ALL, NULL, NULL);
-+                    break;
-+
-+                default:
-+                    break;
-+            }
-+
-+            if (o)
-+                pa_operation_unref(o);
-+
-+            complete_action();
-+            break;
-+        }
-+
-+        case PA_EXT_VOLUME_API_STATE_FAILED:
-+            pa_log("Volume API context failed: %s", pa_strerror(pa_context_errno(c)));
-+
-+            /* If the main context failed too, let's not do anything, because
-+             * calling complete_action() would reset the context error code to
-+             * PA_ERR_BADSTATE, meaning that the original error code would be
-+             * lost. */
-+            if (pa_context_get_state(c) == PA_CONTEXT_FAILED)
-+                break;
-+
-+            if (action == INFO || (action == LIST && !list_type) || action == SUBSCRIBE) {
-+                /* In these cases we shouldn't exit with an error if the volume
-+                 * API happens to be or become unavailable. If we haven't yet
-+                 * connected to the volume API, then we need to complete the
-+                 * "connect to volume API" action. */
-+
-+                if (!volume_api_connected)
-+                    complete_action();
-+            } else
-+                quit(1);
-+
-+            break;
-+
-+        default:
-+            break;
-+    }
-+}
-+
-+static void connect_to_volume_api(void) {
-+    int r;
-+
-+    pa_assert(context);
-+
-+    pa_ext_volume_api_set_state_callback(context, volume_api_state_cb, NULL);
-+
-+    r = pa_ext_volume_api_connect(context);
-+    if (r >= 0)
-+        actions++;
-+}
-+
- static void context_state_callback(pa_context *c, void *userdata) {
-     pa_operation *o = NULL;
-@@ -1215,6 +1797,7 @@ static void context_state_callback(pa_context *c, void *userdata) {
-                 case INFO:
-                     o = pa_context_get_server_info(c, get_server_info_callback, NULL);
-+                    connect_to_volume_api();
-                     break;
-                 case PLAY_SAMPLE:
-@@ -1259,7 +1842,14 @@ static void context_state_callback(pa_context *c, void *userdata) {
-                             o = pa_context_get_card_info_list(c, get_card_info_callback, NULL);
-                       else if (pa_streq(list_type, "nodes"))
-                           o = pa_ext_node_manager_read_nodes(c, node_list_callback, NULL);
--                        else
-+                        else if (pa_streq(list_type, "volume-controls")
-+                                     || pa_streq(list_type, "mute-controls")
-+                                     || pa_streq(list_type, "devices")
-+                                     || pa_streq(list_type, "streams")
-+                                     || pa_streq(list_type, "audio-groups")) {
-+                            connect_to_volume_api();
-+                            o = NULL;
-+                        } else
-                             pa_assert_not_reached();
-                     } else {
-                         o = pa_context_get_module_info_list(c, get_module_info_callback, NULL);
-@@ -1309,6 +1899,7 @@ static void context_state_callback(pa_context *c, void *userdata) {
-                             actions++;
-                         }
-+                        connect_to_volume_api();
-                         o = NULL;
-                     }
-                     break;
-@@ -1442,6 +2033,11 @@ static void context_state_callback(pa_context *c, void *userdata) {
-                     o = pa_context_set_port_latency_offset(c, card_name, port_name, latency_offset, simple_callback, NULL);
-                     break;
-+                case SET_VOLUME_CONTROL_VOLUME:
-+                case SET_MUTE_CONTROL_MUTE:
-+                    connect_to_volume_api();
-+                    break;
-+
-                 case SUBSCRIBE:
-                     pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
-@@ -1457,6 +2053,14 @@ static void context_state_callback(pa_context *c, void *userdata) {
-                                              PA_SUBSCRIPTION_MASK_CARD,
-                                              NULL,
-                                              NULL);
-+
-+                    if (o) {
-+                        pa_operation_unref(o);
-+                        actions++;
-+                        o = NULL;
-+                    }
-+
-+                    connect_to_volume_api();
-                     break;
-               case NODE_CONNECT:
-                   pa_operation_unref(pa_ext_node_manager_connect_nodes(c,
-@@ -1599,6 +2203,9 @@ static void help(const char *argv0) {
-     printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink-input|source-output)-mute", _("#N 1|0|toggle"));
-     printf("%s %s %s %s\n", argv0, _("[options]"), "set-sink-formats", _("#N FORMATS"));
-     printf("%s %s %s %s\n", argv0, _("[options]"), "set-port-latency-offset", _("CARD-NAME|CARD-#N PORT OFFSET"));
-+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-volume-control-volume", _("NAME|#N VOLUME [BALANCE ...]"));
-+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-volume-control-balance", _("NAME|#N BALANCE ..."));
-+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-mute-control-mute", _("NAME|#N 1|0|toggle"));
-     printf("%s %s %s\n",    argv0, _("[options]"), "subscribe");
-     printf(_("\nThe special names @DEFAULT_SINK@, @DEFAULT_SOURCE@ and @DEFAULT_MONITOR@\n"
-              "can be used to specify the default sink, source and monitor.\n"));
-@@ -1613,6 +2220,40 @@ static void help(const char *argv0) {
-              "  -n, --client-name=NAME                How to call this client on the server\n"));
- }
-+static int parse_balance(char *argv[], unsigned first_arg, unsigned n_channels, pa_ext_volume_api_bvolume *bv) {
-+    pa_ext_volume_api_bvolume bv_local;
-+    unsigned i;
-+
-+    pa_assert(n_channels > 0);
-+    pa_assert(bv);
-+
-+    if (n_channels > PA_CHANNELS_MAX) {
-+        pa_log("Too many channels, the maximum is %u.", PA_CHANNELS_MAX);
-+        return -1;
-+    }
-+
-+    bv_local = *bv;
-+
-+    for (i = 0; i < n_channels; i++) {
-+        const char *balance_str;
-+        double balance;
-+
-+        balance_str = argv[first_arg + i];
-+
-+        if (pa_atod(balance_str, &balance) < 0 || !pa_ext_volume_api_balance_valid(balance)) {
-+            pa_log(_("Invalid balance value: %s"), balance_str);
-+            return -1;
-+        }
-+
-+        bv_local.balance[i] = balance;
-+    }
-+
-+    bv_local.channel_map.channels = n_channels;
-+    *bv = bv_local;
-+
-+    return 0;
-+}
-+
- enum {
-     ARG_VERSION = 256
- };
-@@ -1698,15 +2339,19 @@ int main(int argc, char *argv[]) {
-             action = LIST;
-             for (int i = optind+1; i < argc; i++) {
--                if (pa_streq(argv[i], "modules") || pa_streq(argv[i], "clients") ||
--                    pa_streq(argv[i], "sinks")   || pa_streq(argv[i], "sink-inputs") ||
--                    pa_streq(argv[i], "sources") || pa_streq(argv[i], "source-outputs") ||
--                    pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards") || pa_streq(argv[i], "nodes")) {
-+                if (pa_streq(argv[i], "modules")         || pa_streq(argv[i], "clients") ||
-+                    pa_streq(argv[i], "sinks")           || pa_streq(argv[i], "sink-inputs") ||
-+                    pa_streq(argv[i], "sources")         || pa_streq(argv[i], "source-outputs") ||
-+                    pa_streq(argv[i], "samples")         || pa_streq(argv[i], "cards") || pa_streq(argv[i], "nodes") ||
-+                    pa_streq(argv[i], "volume-controls") || pa_streq(argv[i], "mute-controls") ||
-+                    pa_streq(argv[i], "devices")         || pa_streq(argv[i], "streams") ||
-+                    pa_streq(argv[i], "audio-groups")) {
-                     list_type = pa_xstrdup(argv[i]);
-                 } else if (pa_streq(argv[i], "short")) {
-                     short_list_format = true;
-                 } else {
--                    pa_log(_("Specify nothing, or one of: %s"), "modules, sinks, sources, sink-inputs, source-outputs, clients, samples, cards");
-+                    pa_log(_("Specify nothing, or one of: %s"), "modules, sinks, sources, sink-inputs, source-outputs, "
-+                             "clients, samples, cards, volume-controls, mute-controls, devices, streams, audio-groups");
-                     goto quit;
-                 }
-             }
-@@ -2092,6 +2737,58 @@ int main(int argc, char *argv[]) {
-           conn_id = (uint32_t) atoi(argv[optind+1]);
-+        } else if (pa_streq(argv[optind], "set-volume-control-volume")) {
-+            action = SET_VOLUME_CONTROL_VOLUME;
-+
-+            if (argc < optind + 3) {
-+                pa_log(_("You have to specify a volume control name/index and a volume, and optionally balance parameters."));
-+                goto quit;
-+            }
-+
-+            volume_control_name = pa_xstrdup(argv[optind + 1]);
-+
-+            if (parse_volume(argv[optind + 2], &bvolume.volume, &volume_flags) < 0)
-+                goto quit;
-+
-+            volume_valid = true;
-+
-+            if (argc > optind + 3) {
-+                if (parse_balance(argv, optind + 3, argc - (optind + 3), &bvolume) < 0)
-+                    goto quit;
-+
-+                balance_valid = true;
-+            }
-+
-+        } else if (pa_streq(argv[optind], "set-volume-control-balance")) {
-+            action = SET_VOLUME_CONTROL_VOLUME;
-+
-+            if (argc < optind + 3) {
-+                pa_log(_("You have to specify a volume control name/index and balance parameters."));
-+                goto quit;
-+            }
-+
-+            volume_control_name = pa_xstrdup(argv[optind + 1]);
-+
-+            if (parse_balance(argv, optind + 2, argc - (optind + 2), &bvolume) < 0)
-+                goto quit;
-+
-+            balance_valid = true;
-+
-+        } else if (pa_streq(argv[optind], "set-mute-control-mute")) {
-+            action = SET_MUTE_CONTROL_MUTE;
-+
-+            if (argc != optind + 3) {
-+                pa_log(_("You have to specify a mute control name/index and a mute value."));
-+                goto quit;
-+            }
-+
-+            mute_control_name = pa_xstrdup(argv[optind + 1]);
-+
-+            if ((mute = parse_mute(argv[optind + 2])) == INVALID_MUTE) {
-+                pa_log(_("Invalid mute specification"));
-+                goto quit;
-+            }
-+
-       } else if (pa_streq(argv[optind], "help")) {
-             help(bn);
-             ret = 0;
-@@ -2154,6 +2851,8 @@ quit:
-     pa_xfree(profile_name);
-     pa_xfree(port_name);
-     pa_xfree(formats);
-+    pa_xfree(mute_control_name);
-+    pa_xfree(volume_control_name);
-     if (sndfile)
-         sf_close(sndfile);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0081-Add-module-audio-groups.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0081-Add-module-audio-groups.patch
deleted file mode 100644 (file)
index b918bff..0000000
+++ /dev/null
@@ -1,1425 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 21 May 2014 14:08:40 +0300
-Subject: Add module-audio-groups
-
-Change-Id: Iaa0284e0537785ed245caae6e49544477ca246b9
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/Makefile.am                                    |   13 +-
- src/daemon/default.pa.in                           |    4 +
- src/modules/audio-groups/audio-groups.conf.example |   28 +
- src/modules/audio-groups/module-audio-groups.c     | 1317 ++++++++++++++++++++
- 4 files changed, 1360 insertions(+), 2 deletions(-)
- create mode 100644 src/modules/audio-groups/audio-groups.conf.example
- create mode 100644 src/modules/audio-groups/module-audio-groups.c
-
-diff --git a/src/Makefile.am b/src/Makefile.am
-index e075c1d..a6bb319 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -1082,6 +1082,12 @@ libvolume_api_la_SOURCES = \
- libvolume_api_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
- libvolume_api_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la
-+# Audio Groups
-+module_audio_groups_la_SOURCES = modules/audio-groups/module-audio-groups.c
-+module_audio_groups_la_LDFLAGS = $(MODULE_LDFLAGS)
-+module_audio_groups_la_LIBADD = $(MODULE_LIBADD) libvolume-api.la
-+module_audio_groups_la_CFLAGS = $(AM_CFLAGS)
-+
- if HAVE_ESOUND
- libprotocol_esound_la_SOURCES = pulsecore/protocol-esound.c pulsecore/protocol-esound.h pulsecore/esound.h
- libprotocol_esound_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
-@@ -1168,7 +1174,8 @@ modlibexec_LTLIBRARIES += \
-               module-switch-on-port-available.la \
-               module-filter-apply.la \
-               module-filter-heuristics.la \
--              module-role-ducking.la
-+              module-role-ducking.la \
-+              module-audio-groups.la
- if HAVE_ESOUND
- modlibexec_LTLIBRARIES += \
-@@ -1505,7 +1512,9 @@ SYMDEF_FILES = \
-               module-switch-on-connect-symdef.h \
-               module-switch-on-port-available-symdef.h \
-               module-filter-apply-symdef.h \
--              module-filter-heuristics-symdef.h
-+              module-filter-heuristics-symdef.h \
-+              module-audio-groups-symdef.h
-+
- if USE_SAMSUNG_POLICY
- SYMDEF_FILES += \
-               module-policy-symdef.h
-diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
-index a21ae04..7cf52a4 100755
---- a/src/daemon/default.pa.in
-+++ b/src/daemon/default.pa.in
-@@ -193,6 +193,10 @@ ifelse(@HAVE_X11@, 1, [dnl
- load-module module-volume-api
- .endif
-+.ifexists module-audio-groups
-+load-module module-audio-groups
-+.endif
-+
- ### Make some devices default
- #set-default-sink output
- #set-default-source input
-diff --git a/src/modules/audio-groups/audio-groups.conf.example b/src/modules/audio-groups/audio-groups.conf.example
-new file mode 100644
-index 0000000..8acdb76
---- /dev/null
-+++ b/src/modules/audio-groups/audio-groups.conf.example
-@@ -0,0 +1,28 @@
-+[General]
-+audio-groups = x-example-call-downlink-audio-group x-example-default-output-audio-group x-example-music-output-audio-group
-+streams = phone-output music-output default-output
-+
-+[AudioGroup x-example-call-downlink-audio-group]
-+volume-control = create
-+mute-control = none
-+
-+[AudioGroup x-example-default-output-audio-group]
-+volume-control = create
-+mute-control = none
-+
-+[AudioGroup x-example-music-output-audio-group]
-+volume-control = bind:AudioGroup:x-example-default-output-audio-group
-+
-+[Stream phone-output]
-+match = (direction output AND property media.role=phone)
-+audio-group-for-volume = x-example-call-downlink-audio-group
-+audio-group-for-mute = x-example-call-downlink-audio-group
-+
-+[Stream music-output]
-+match = (direction output AND property media.role=music)
-+audio-group-for-volume = x-example-music-output-audio-group
-+audio-group-for-mute = x-example-music-output-audio-group
-+
-+[Stream default-output]
-+audio-group-for-volume = x-example-default-output-audio-group
-+audio-group-for-mute = x-example-default-output-audio-group
-diff --git a/src/modules/audio-groups/module-audio-groups.c b/src/modules/audio-groups/module-audio-groups.c
-new file mode 100644
-index 0000000..320847c
---- /dev/null
-+++ b/src/modules/audio-groups/module-audio-groups.c
-@@ -0,0 +1,1317 @@
-+/***
-+  This file is part of PulseAudio.
-+
-+  Copyright 2014 Intel Corporation
-+
-+  PulseAudio is free software; you can redistribute it and/or modify
-+  it under the terms of the GNU Lesser General Public License as published
-+  by the Free Software Foundation; either version 2.1 of the License,
-+  or (at your option) any later version.
-+
-+  PulseAudio is distributed in the hope that it will be useful, but
-+  WITHOUT ANY WARRANTY; without even the implied warranty of
-+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+  General Public License for more details.
-+
-+  You should have received a copy of the GNU Lesser General Public License
-+  along with PulseAudio; if not, write to the Free Software
-+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-+  USA.
-+***/
-+
-+#ifdef HAVE_CONFIG_H
-+#include <config.h>
-+#endif
-+
-+#include <string.h>
-+
-+#include <pulse/xmalloc.h>
-+
-+#include <pulsecore/core-util.h>
-+#include <pulsecore/dynarray.h>
-+#include <pulsecore/module.h>
-+#include <pulsecore/modargs.h>
-+#include <pulsecore/conf-parser.h>
-+#include <pulsecore/hashmap.h>
-+
-+#include <modules/volume-api/sstream.h>
-+#include <modules/volume-api/volume-control.h>
-+#include <modules/volume-api/audio-group.h>
-+
-+#include "module-audio-groups-symdef.h"
-+
-+PA_MODULE_AUTHOR("Ismo Puustinen");
-+PA_MODULE_DESCRIPTION("Create audio groups and classify streams to them");
-+PA_MODULE_VERSION(PACKAGE_VERSION);
-+PA_MODULE_LOAD_ONCE(true);
-+
-+#ifndef AUDIO_GROUP_CONFIG
-+#define AUDIO_GROUP_CONFIG "audio-groups.conf"
-+#endif
-+
-+enum match_direction {
-+    match_direction_unknown = 0,
-+    match_direction_input,
-+    match_direction_output,
-+};
-+
-+/* logical expressions */
-+
-+struct literal {
-+
-+    /* TODO: this might be parsed to some faster-to-check format? */
-+
-+    char *property_name;
-+    char *property_value;
-+    enum match_direction stream_direction;
-+
-+    bool negation;
-+    PA_LLIST_FIELDS(struct literal);
-+};
-+
-+struct conjunction {
-+    /* a conjunction of literals */
-+    PA_LLIST_HEAD(struct literal, literals);
-+    PA_LLIST_FIELDS(struct conjunction);
-+};
-+
-+struct expression {
-+    /* this is in disjunctive normal form, so a disjunction of conjunctions */
-+    PA_LLIST_HEAD(struct conjunction, conjunctions);
-+};
-+
-+/* data gathered from settings */
-+
-+enum control_action {
-+    CONTROL_ACTION_NONE,
-+    CONTROL_ACTION_CREATE,
-+    CONTROL_ACTION_BIND,
-+};
-+
-+struct audio_group {
-+    struct userdata *userdata;
-+    char *id;
-+    char *description;
-+    enum control_action volume_control_action;
-+    enum control_action mute_control_action;
-+    pa_binding_target_info *volume_control_target_info;
-+    pa_binding_target_info *mute_control_target_info;
-+
-+    /* official audio group */
-+    pa_audio_group *group;
-+
-+    struct audio_group_control *volume_control;
-+    struct audio_group_control *mute_control;
-+
-+    bool unlinked;
-+};
-+
-+struct stream {
-+    struct userdata *userdata;
-+    char *id;
-+    enum match_direction direction;
-+    char *audio_group_name_for_volume;
-+    char *audio_group_name_for_mute;
-+    pa_audio_group *audio_group_for_volume;
-+    pa_audio_group *audio_group_for_mute;
-+    pa_binding_target_info *volume_control_target_info;
-+    pa_binding_target_info *mute_control_target_info;
-+    struct expression *rule;
-+
-+    bool unlinked;
-+};
-+
-+struct userdata {
-+    pa_hashmap *audio_groups; /* name -> struct audio_group */
-+    pa_dynarray *streams; /* struct stream */
-+    pa_hook_slot *new_stream_volume;
-+    pa_hook_slot *new_stream_mute;
-+
-+    pa_volume_api *api;
-+
-+    /* The following fields are only used during initialization. */
-+    pa_hashmap *audio_group_names; /* name -> name (hashmap-as-a-set) */
-+    pa_hashmap *unused_audio_groups; /* name -> struct audio_group */
-+    pa_dynarray *stream_names;
-+    pa_hashmap *unused_streams; /* name -> struct stream */
-+};
-+
-+static const char* const valid_modargs[] = {
-+    "filename",
-+    NULL
-+};
-+
-+static void audio_group_unlink(struct audio_group *group);
-+
-+static void print_literal(struct literal *l);
-+static void print_conjunction(struct conjunction *c);
-+static void print_expression(struct expression *e);
-+static void delete_expression(struct expression *e);
-+
-+static struct audio_group *audio_group_new(struct userdata *u, const char *name) {
-+    struct audio_group *group;
-+
-+    pa_assert(u);
-+    pa_assert(name);
-+
-+    group = pa_xnew0(struct audio_group, 1);
-+    group->userdata = u;
-+    group->id = pa_xstrdup(name);
-+    group->description = pa_xstrdup(name);
-+    group->volume_control_action = CONTROL_ACTION_NONE;
-+    group->mute_control_action = CONTROL_ACTION_NONE;
-+
-+    return group;
-+}
-+
-+static int audio_group_put(struct audio_group *group) {
-+    int r;
-+
-+    pa_assert(group);
-+
-+    r = pa_audio_group_new(group->userdata->api, group->id, group->description, &group->group);
-+    if (r < 0)
-+        goto fail;
-+
-+    switch (group->volume_control_action) {
-+        case CONTROL_ACTION_NONE:
-+            break;
-+
-+        case CONTROL_ACTION_CREATE:
-+            pa_audio_group_set_have_own_volume_control(group->group, true);
-+            pa_audio_group_set_volume_control(group->group, group->group->own_volume_control);
-+            break;
-+
-+        case CONTROL_ACTION_BIND:
-+            pa_audio_group_bind_volume_control(group->group, group->volume_control_target_info);
-+            break;
-+    }
-+
-+    switch (group->mute_control_action) {
-+        case CONTROL_ACTION_NONE:
-+            break;
-+
-+        case CONTROL_ACTION_CREATE:
-+            pa_audio_group_set_have_own_mute_control(group->group, true);
-+            pa_audio_group_set_mute_control(group->group, group->group->own_mute_control);
-+            break;
-+
-+        case CONTROL_ACTION_BIND:
-+            pa_audio_group_bind_mute_control(group->group, group->mute_control_target_info);
-+            break;
-+    }
-+
-+    pa_audio_group_put(group->group);
-+
-+    return 0;
-+
-+fail:
-+    audio_group_unlink(group);
-+
-+    return r;
-+}
-+
-+static void audio_group_unlink(struct audio_group *group) {
-+    pa_assert(group);
-+
-+    if (group->unlinked)
-+        return;
-+
-+    group->unlinked = true;
-+
-+    if (group->group) {
-+        pa_audio_group_free(group->group);
-+        group->group = NULL;
-+    }
-+}
-+
-+static void audio_group_free(struct audio_group *group) {
-+    pa_assert(group);
-+
-+    if (!group->unlinked)
-+        audio_group_unlink(group);
-+
-+    if (group->mute_control_target_info)
-+        pa_binding_target_info_free(group->mute_control_target_info);
-+
-+    if (group->volume_control_target_info)
-+        pa_binding_target_info_free(group->volume_control_target_info);
-+
-+    pa_xfree(group->description);
-+    pa_xfree(group->id);
-+    pa_xfree(group);
-+}
-+
-+static void audio_group_set_description(struct audio_group *group, const char *description) {
-+    pa_assert(group);
-+    pa_assert(description);
-+
-+    pa_xfree(group->description);
-+    group->description = pa_xstrdup(description);
-+}
-+
-+static void audio_group_set_volume_control_action(struct audio_group *group, enum control_action action,
-+                                                  pa_binding_target_info *target_info) {
-+    pa_assert(group);
-+    pa_assert((action == CONTROL_ACTION_BIND) ^ !target_info);
-+
-+    group->volume_control_action = action;
-+
-+    if (group->volume_control_target_info)
-+        pa_binding_target_info_free(group->volume_control_target_info);
-+
-+    if (action == CONTROL_ACTION_BIND)
-+        group->volume_control_target_info = pa_binding_target_info_copy(target_info);
-+    else
-+        group->volume_control_target_info = NULL;
-+}
-+
-+static void audio_group_set_mute_control_action(struct audio_group *group, enum control_action action,
-+                                                pa_binding_target_info *target_info) {
-+    pa_assert(group);
-+    pa_assert((action == CONTROL_ACTION_BIND) ^ !target_info);
-+
-+    group->mute_control_action = action;
-+
-+    if (group->mute_control_target_info)
-+        pa_binding_target_info_free(group->mute_control_target_info);
-+
-+    if (action == CONTROL_ACTION_BIND)
-+        group->mute_control_target_info = pa_binding_target_info_copy(target_info);
-+    else
-+        group->mute_control_target_info = NULL;
-+}
-+
-+static struct stream *stream_new(struct userdata *u, const char *name) {
-+    struct stream *stream;
-+
-+    pa_assert(u);
-+    pa_assert(name);
-+
-+    stream = pa_xnew0(struct stream, 1);
-+    stream->userdata = u;
-+    stream->id = pa_xstrdup(name);
-+    stream->direction = match_direction_unknown;
-+
-+    return stream;
-+}
-+
-+static void stream_put(struct stream *stream) {
-+    pa_assert(stream);
-+
-+    if (stream->audio_group_name_for_volume) {
-+        stream->audio_group_for_volume = pa_hashmap_get(stream->userdata->audio_groups, stream->audio_group_name_for_volume);
-+        if (stream->audio_group_for_volume)
-+            stream->volume_control_target_info =
-+                    pa_binding_target_info_new(PA_AUDIO_GROUP_BINDING_TARGET_TYPE, stream->audio_group_for_volume->name,
-+                                               PA_AUDIO_GROUP_BINDING_TARGET_FIELD_VOLUME_CONTROL);
-+        else
-+            pa_log("Stream %s refers to undefined audio group %s.", stream->id, stream->audio_group_name_for_volume);
-+    }
-+
-+    if (stream->audio_group_name_for_mute) {
-+        stream->audio_group_for_mute = pa_hashmap_get(stream->userdata->audio_groups, stream->audio_group_name_for_mute);
-+        if (stream->audio_group_for_mute)
-+            stream->mute_control_target_info =
-+                    pa_binding_target_info_new(PA_AUDIO_GROUP_BINDING_TARGET_TYPE, stream->audio_group_for_mute->name,
-+                                               PA_AUDIO_GROUP_BINDING_TARGET_FIELD_MUTE_CONTROL);
-+        else
-+            pa_log("Stream %s refers to undefined audio group %s.", stream->id, stream->audio_group_name_for_volume);
-+    }
-+}
-+
-+static void stream_unlink(struct stream *stream) {
-+    pa_assert(stream);
-+
-+    if (stream->unlinked)
-+        return;
-+
-+    if (stream->mute_control_target_info) {
-+        pa_binding_target_info_free(stream->mute_control_target_info);
-+        stream->mute_control_target_info = NULL;
-+    }
-+
-+    if (stream->volume_control_target_info) {
-+        pa_binding_target_info_free(stream->volume_control_target_info);
-+        stream->volume_control_target_info = NULL;
-+    }
-+
-+    stream->unlinked = true;
-+}
-+
-+static void stream_free(struct stream *stream) {
-+    pa_assert(stream);
-+
-+    if (!stream->unlinked)
-+        stream_unlink(stream);
-+
-+    if (stream->rule)
-+        delete_expression(stream->rule);
-+
-+    pa_xfree(stream->audio_group_name_for_mute);
-+    pa_xfree(stream->audio_group_name_for_volume);
-+    pa_xfree(stream->id);
-+    pa_xfree(stream);
-+}
-+
-+static void stream_set_audio_group_name_for_volume(struct stream *stream, const char *name) {
-+    pa_assert(stream);
-+
-+    pa_xfree(stream->audio_group_name_for_volume);
-+    stream->audio_group_name_for_volume = pa_xstrdup(name);
-+}
-+
-+static void stream_set_audio_group_name_for_mute(struct stream *stream, const char *name) {
-+    pa_assert(stream);
-+
-+    pa_xfree(stream->audio_group_name_for_mute);
-+    stream->audio_group_name_for_mute = pa_xstrdup(name);
-+}
-+
-+/* stream classification */
-+
-+static bool match_predicate(struct literal *l, pas_stream *d) {
-+
-+    if (l->stream_direction != match_direction_unknown) {
-+        /* check the stream direction; _sink inputs_ are always _outputs_ */
-+
-+        if ((d->direction == PA_DIRECTION_OUTPUT && l->stream_direction == match_direction_output) ||
-+            ((d->direction == PA_DIRECTION_INPUT && l->stream_direction == match_direction_input))) {
-+            return true;
-+        }
-+    }
-+    else if (l->property_name && l->property_value) {
-+        /* check the property from the property list */
-+
-+        if (pa_proplist_contains(d->proplist, l->property_name) &&
-+                strcmp(pa_proplist_gets(d->proplist, l->property_name), l->property_value) == 0)
-+            return true;
-+    }
-+
-+    /* no match */
-+    return false;
-+}
-+
-+static bool match_rule(struct expression *e, pas_stream *d) {
-+
-+    struct conjunction *c;
-+
-+    PA_LLIST_FOREACH(c, e->conjunctions) {
-+        struct literal *l;
-+        bool and_success = true;
-+        PA_LLIST_FOREACH(l, c->literals) {
-+            if (!match_predicate(l, d)) {
-+                /* at least one fail for conjunction */
-+                and_success = false;
-+                break;
-+            }
-+        }
-+
-+        if (and_success) {
-+            /* at least one match for disjunction */
-+            return true;
-+        }
-+    }
-+
-+    /* no matches */
-+    return false;
-+}
-+
-+static void classify_stream(struct userdata *u, pas_stream *new_data, bool mute) {
-+    /* do the classification here */
-+
-+    struct stream *stream = NULL;
-+    unsigned idx;
-+
-+    /* go through the stream match definitions in given order */
-+
-+    PA_DYNARRAY_FOREACH(stream, u->streams, idx) {
-+        if (stream->rule && match_rule(stream->rule, new_data)) {
-+            pa_log_info("stream %s (%s) match with rule %s:", new_data->name, new_data->description, stream->id);
-+            print_expression(stream->rule);
-+
-+            if (mute) {
-+                if (new_data->use_default_mute_control && stream->audio_group_for_mute)
-+                    pas_stream_bind_mute_control(new_data, stream->mute_control_target_info);
-+            } else {
-+                if (new_data->use_default_volume_control && stream->audio_group_for_volume)
-+                    pas_stream_bind_volume_control(new_data, stream->volume_control_target_info);
-+            }
-+
-+            return;
-+        }
-+    }
-+
-+    /* no matches, don't touch the volumes */
-+}
-+
-+static pa_hook_result_t set_volume_control_cb(
-+        void *hook_data,
-+        pas_stream *new_data,
-+        struct userdata *u) {
-+
-+    pa_assert(new_data);
-+    pa_assert(u);
-+
-+    classify_stream(u, new_data, false);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t set_mute_control_cb(
-+        void *hook_data,
-+        pas_stream *new_data,
-+        struct userdata *u) {
-+
-+    pa_assert(new_data);
-+    pa_assert(u);
-+
-+    classify_stream(u, new_data, true);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+/* parser for configuration file */
-+
-+/*
-+    Parse the match expression. The syntax is this:
-+
-+    OPER           := "AND" | "OR"
-+    OPEN_BRACE     := "("
-+    CLOSE_BRACE    := ")"
-+    EXPR           := OPEN_BRACE EXPR OPER EXPR CLOSE_BRACE | VAR
-+    VAR            := LIT | "NEG" LIT
-+    LIT            := PREDICATE (defined by rule semantics)
-+
-+    In addition there is a requirement that the expressions need to be in
-+    disjunctive normal form. It means that if there is an expression that
-+    has AND operator, there may not be any OR operators in its subexpressions.
-+
-+    Example expressions:
-+
-+    (foo)
-+    (foo AND bar)
-+    (foo OR (bar AND xxx))
-+    (NEG foo OR (bar AND NEG xxx))
-+
-+    The predicate here is the single rule that is matched against the new sink
-+    input. The syntax is this:
-+
-+    PREDICATE      := "direction" DIRECTION  | "property" PROPERTY
-+    DIRECTION      := "input" | "output"
-+    PROPERTY       := PROPERTY_NAME "=" PROPERTY_VALUE
-+    PROPERTY_NAME  := STRING
-+    PROPERTY_VALUE := STRING
-+
-+    The allowed characters for STRING are standard ascii characters. Not
-+    allowed substrings are the reserved words "AND", "OR", "(", ")", "NEG" and
-+    "=".
-+
-+    Complete examples:
-+
-+    (property application.process.binary=paplay)
-+
-+    (property media.role=music AND direction input)
-+
-+    (property application.process.binary=paplay OR (direction input OR direction output))
-+*/
-+
-+static void print_literal(struct literal *l) {
-+    if (l->stream_direction != match_direction_unknown) {
-+        pa_log_info("       %sstream direction %s",
-+                l->negation ? "NEG " : "",
-+                l->stream_direction == match_direction_input ? "input" : "output");
-+    }
-+    else {
-+        pa_log_info("       %sproperty %s == %s",
-+                l->negation ? "NEG " : "",
-+                l->property_name ? l->property_name : "NULL",
-+                l->property_value ? l->property_value : "NULL");
-+    }
-+}
-+
-+static void print_conjunction(struct conjunction *c) {
-+    struct literal *l;
-+    pa_log_info("   conjunction for literals:");
-+    PA_LLIST_FOREACH(l, c->literals) {
-+        print_literal(l);
-+    }
-+}
-+
-+static void print_expression(struct expression *e) {
-+    struct conjunction *c;
-+    pa_log_info("disjunction for conjunctions:");
-+    PA_LLIST_FOREACH(c, e->conjunctions) {
-+        print_conjunction(c);
-+    }
-+}
-+
-+static void delete_literal(struct literal *l) {
-+
-+    if (!l)
-+        return;
-+
-+    pa_xfree(l->property_name);
-+    pa_xfree(l->property_value);
-+    pa_xfree(l);
-+}
-+
-+static void delete_conjunction(struct conjunction *c) {
-+    struct literal *l;
-+
-+    if (!c)
-+        return;
-+
-+    PA_LLIST_FOREACH(l, c->literals) {
-+        delete_literal(l);
-+    }
-+
-+    pa_xfree(c);
-+}
-+
-+static void delete_expression(struct expression *e) {
-+    struct conjunction *c;
-+
-+    PA_LLIST_FOREACH(c, e->conjunctions) {
-+        delete_conjunction(c);
-+    }
-+
-+    pa_xfree(e);
-+}
-+
-+enum logic_operator {
-+    operator_not_set = 0,
-+    operator_and,
-+    operator_or,
-+};
-+
-+struct expression_token {
-+    struct expression_token *left;
-+    struct expression_token *right;
-+
-+    enum logic_operator oper;
-+
-+    struct literal_token *lit;
-+};
-+
-+struct literal_token {
-+    bool negation;
-+    char *var;
-+};
-+
-+static void delete_literal_token(struct literal_token *l) {
-+
-+    if (!l)
-+        return;
-+
-+    pa_xfree(l->var);
-+    pa_xfree(l);
-+}
-+
-+static void delete_expression_token(struct expression_token *e) {
-+
-+    if (!e)
-+        return;
-+
-+    delete_expression_token(e->left);
-+    delete_expression_token(e->right);
-+    delete_literal_token(e->lit);
-+
-+    e->left = NULL;
-+    e->right = NULL;
-+    e->lit = NULL;
-+
-+    pa_xfree(e);
-+}
-+
-+static struct expression_token *parse_rule_internal(const char *rule, bool disjunction_allowed) {
-+
-+    int len = strlen(rule);
-+    struct expression_token *et;
-+    char *p;
-+    int brace_count = 0;
-+    bool braces_present = false;
-+    char left_buf[len];
-+    char right_buf[len];
-+
-+#if 0
-+    /* check if the rule is still valid */
-+
-+    if (len < 2)
-+        return NULL;
-+
-+    if (rule[0] != '(' || rule[len-1] != ')')
-+        return NULL;
-+#endif
-+
-+    et = pa_xnew0(struct expression_token, 1);
-+
-+    if (!et)
-+        return NULL;
-+
-+    /* count the braces -- we want to find the case when there is only one brace open */
-+
-+    p = (char *) rule;
-+
-+    while (*p) {
-+        if (*p == '(') {
-+            braces_present = true;
-+            brace_count++;
-+        }
-+        else if (*p == ')') {
-+            brace_count--;
-+        }
-+
-+        if (brace_count == 1) {
-+
-+            /* the parser is recursive and just goes down the tree on the
-+             * topmost level (where the brace count is 1). If there are no
-+             * braces this is a literal */
-+
-+            /* find the operator AND or OR */
-+
-+            if (strncmp(p, "AND", 3) == 0) {
-+
-+                /* copy parts */
-+                char *begin_left = (char *) rule+1;
-+                char *begin_right = p+3;
-+
-+                int left_len = p - rule - 1; /* minus '(' */
-+                int right_len = len - 3 - left_len - 2; /* minus AND and '(' and ')'*/
-+
-+                memcpy(left_buf, begin_left, left_len);
-+                left_buf[left_len] = '\0';
-+                memcpy(right_buf, begin_right, right_len);
-+                right_buf[right_len] = '\0';
-+
-+                et->left = parse_rule_internal(left_buf, false);
-+                et->right = parse_rule_internal(right_buf, false);
-+                et->oper = operator_and;
-+
-+                if (!et->left || !et->right) {
-+                    delete_expression_token(et);
-+                    return NULL;
-+                }
-+
-+                return et;
-+            }
-+            else if (strncmp(p, "OR", 2) == 0) {
-+
-+                char *begin_left = (char *) rule+1;
-+                char *begin_right = p+2;
-+
-+                int left_len = p - rule - 1; /* minus '(' */
-+                int right_len = len - 2 - left_len - 2; /* minus OR and '(' and ')'*/
-+
-+                if (!disjunction_allowed) {
-+                    pa_log_error("logic expression not in dnf");
-+                    delete_expression_token(et);
-+                    return NULL;
-+                }
-+
-+                memcpy(left_buf, begin_left, left_len);
-+                left_buf[left_len] = '\0';
-+                memcpy(right_buf, begin_right, right_len);
-+                right_buf[right_len] = '\0';
-+
-+                et->left = parse_rule_internal(left_buf, true);
-+                et->right = parse_rule_internal(right_buf, true);
-+                et->oper = operator_or;
-+
-+                if (!et->left || !et->right) {
-+                    delete_expression_token(et);
-+                    return NULL;
-+                }
-+
-+                return et;
-+            }
-+            /* else a literal which is inside braces */
-+        }
-+
-+        p++;
-+    }
-+
-+    if (brace_count != 0) {
-+        /* the input is not valid */
-+        pa_log_error("mismatched braces in logic expression");
-+        delete_expression_token(et);
-+        return NULL;
-+    }
-+    else {
-+        /* this is a literal */
-+        char *begin_lit;
-+        char buf[strlen(rule)+1];
-+
-+        struct literal_token *lit = pa_xnew0(struct literal_token, 1);
-+        if (!lit) {
-+            delete_expression_token(et);
-+            return NULL;
-+        }
-+
-+        if (braces_present) {
-+            /* remove all braces */
-+            char *k;
-+            char *l;
-+
-+            k = (char *) rule;
-+            l = buf;
-+
-+            while (*k) {
-+                if (*k == '(' || *k == ')') {
-+                    k++;
-+                    continue;
-+                }
-+
-+                *l = *k;
-+                l++;
-+                k++;
-+            }
-+            *l = '\0';
-+        }
-+        else {
-+            strncpy(buf, rule, sizeof(buf));
-+        }
-+
-+        if (strncmp(buf, "NEG", 3) == 0) {
-+            begin_lit = (char *) buf + 3;
-+            lit->negation = true;
-+        }
-+        else {
-+            begin_lit = (char *) buf;
-+            lit->negation = false;
-+        }
-+
-+        lit->var = pa_xstrdup(begin_lit);
-+        et->lit = lit;
-+    }
-+
-+    return et;
-+}
-+
-+static bool gather_literal(struct expression_token *et, struct literal *l) {
-+#define PROPERTY_KEYWORD "property"
-+#define DIRECTION_KEYWORD "direction"
-+#define DIRECTION_VALUE_INPUT "input"
-+#define DIRECTION_VALUE_OUTPUT "output"
-+
-+    char *p = et->lit->var;
-+    int len = strlen(et->lit->var);
-+
-+    l->negation = et->lit->negation;
-+
-+    if (strncmp(p, PROPERTY_KEYWORD, strlen(PROPERTY_KEYWORD)) == 0) {
-+        char name[len];
-+        char value[len];
-+        int i = 0;
-+
-+        p += strlen(PROPERTY_KEYWORD);
-+
-+        /* parse the property pair: name=value */
-+
-+        while (*p && *p != '=') {
-+            name[i++] = *p;
-+            p++;
-+        }
-+
-+        /* check if we really found '=' */
-+
-+        if (*p != '=') {
-+            pa_log_error("property syntax broken for '%s'", et->lit->var);
-+            goto error;
-+        }
-+
-+        name[i] = '\0';
-+
-+        p++;
-+        i = 0;
-+
-+        while (*p) {
-+            value[i++] = *p;
-+            p++;
-+        }
-+
-+        value[i] = '\0';
-+
-+        l->property_name = pa_xstrdup(name);
-+        l->property_value = pa_xstrdup(value);
-+    }
-+    else if (strncmp(p, DIRECTION_KEYWORD, strlen(DIRECTION_KEYWORD)) == 0) {
-+        p += strlen(DIRECTION_KEYWORD);
-+
-+        if (strncmp(p, DIRECTION_VALUE_INPUT, strlen(DIRECTION_VALUE_INPUT)) == 0) {
-+            l->stream_direction = match_direction_input;
-+        }
-+        else if (strncmp(p, DIRECTION_VALUE_OUTPUT, strlen(DIRECTION_VALUE_OUTPUT)) == 0) {
-+            l->stream_direction = match_direction_output;
-+        }
-+        else {
-+            pa_log_error("unknown direction(%s): %s", et->lit->var, p);
-+            goto error;
-+        }
-+    }
-+    else {
-+        pa_log_error("not able to parse the value: '%s'", et->lit->var);
-+        goto error;
-+    }
-+
-+    return true;
-+
-+error:
-+    return false;
-+
-+#undef DIRECTION_VALUE_OUTPUT
-+#undef DIRECTION_VALUE_INPUT
-+#undef DIRECTION_KEYWORD
-+#undef PROPERTY_KEYWORD
-+}
-+
-+static bool gather_conjunction(struct expression_token *et, struct conjunction *c) {
-+
-+    if (et->oper == operator_and) {
-+        if (!gather_conjunction(et->left, c) ||
-+            !gather_conjunction(et->right, c))
-+            return false;
-+    }
-+    else {
-+        /* literal */
-+        struct literal *l = pa_xnew0(struct literal, 1);
-+
-+        if (!l)
-+            return false;
-+
-+        gather_literal(et, l);
-+
-+        PA_LLIST_PREPEND(struct literal, c->literals, l);
-+    }
-+
-+    return true;
-+}
-+
-+static bool gather_expression(struct expression *e, struct expression_token *et) {
-+
-+    if (et->oper == operator_or) {
-+        if (!gather_expression(e, et->right) ||
-+            !gather_expression(e, et->left))
-+            return false;
-+    }
-+    else {
-+        /* conjunction or literal */
-+        struct conjunction *c = pa_xnew0(struct conjunction, 1);
-+        if (!gather_conjunction(et, c))
-+            return false;
-+
-+        PA_LLIST_PREPEND(struct conjunction, e->conjunctions, c);
-+    }
-+
-+    return true;
-+}
-+
-+static struct expression *parse_rule(const char *rule_string) {
-+    char *k, *l;
-+    struct expression *e = NULL;
-+    int len;
-+    char *buf = NULL;
-+    struct expression_token *et = NULL;
-+
-+    if (!rule_string)
-+        goto error;
-+
-+    len = strlen(rule_string);
-+
-+    buf = (char *) pa_xmalloc0(len);
-+
-+    if (!buf)
-+        goto error;
-+
-+    /* remove whitespace */
-+
-+    k = (char *) rule_string;
-+    l = buf;
-+
-+    while (*k) {
-+        if (*k == ' ') {
-+            k++;
-+            continue;
-+        }
-+
-+        *l = *k;
-+        l++;
-+        k++;
-+    }
-+
-+    /* et is the root of an expression tree */
-+    et = parse_rule_internal(buf, true);
-+
-+    if (!et)
-+        goto error;
-+
-+    e = pa_xnew0(struct expression, 1);
-+
-+    if (!e)
-+        goto error;
-+
-+    /* gather expressions to actual match format */
-+    gather_expression(e, et);
-+
-+#if 1
-+    print_expression(e);
-+#endif
-+
-+    /* free memory */
-+    delete_expression_token(et);
-+    pa_xfree(buf);
-+
-+    return e;
-+
-+error:
-+    delete_expression_token(et);
-+    pa_xfree(buf);
-+    pa_xfree(e);
-+    return NULL;
-+}
-+
-+static int parse_audio_groups(pa_config_parser_state *state) {
-+    struct userdata *u;
-+    char *name;
-+    const char *split_state = NULL;
-+
-+    pa_assert(state);
-+
-+    u = state->userdata;
-+
-+    pa_hashmap_remove_all(u->audio_group_names);
-+
-+    while ((name = pa_split_spaces(state->rvalue, &split_state)))
-+        pa_hashmap_put(u->audio_group_names, name, name);
-+
-+    return 0;
-+}
-+
-+static int parse_streams(pa_config_parser_state *state) {
-+    struct userdata *u;
-+    char *name;
-+    const char *split_state = NULL;
-+
-+    pa_assert(state);
-+
-+    u = state->userdata;
-+
-+    pa_dynarray_remove_all(u->stream_names);
-+
-+    while ((name = pa_split_spaces(state->rvalue, &split_state))) {
-+        const char *name2;
-+        unsigned idx;
-+        bool duplicate = false;
-+
-+        /* Avoid adding duplicates in u->stream_names. */
-+        PA_DYNARRAY_FOREACH(name2, u->stream_names, idx) {
-+            if (pa_streq(name, name2)) {
-+                duplicate = true;
-+                break;
-+            }
-+        }
-+
-+        if (duplicate) {
-+            pa_xfree(name);
-+            continue;
-+        }
-+
-+        pa_dynarray_append(u->stream_names, name);
-+    }
-+
-+    return 0;
-+}
-+
-+static int parse_common(pa_config_parser_state *state) {
-+#define AUDIOGROUP_START "AudioGroup "
-+#define STREAM_START "Stream "
-+#define BIND_KEYWORD "bind:"
-+#define NONE_KEYWORD "none"
-+
-+    char *section;
-+    struct userdata *u = (struct userdata *) state->userdata;
-+    int r;
-+    pa_binding_target_info *target_info;
-+
-+    pa_assert(state);
-+
-+    section = state->section;
-+    if (!section)
-+        goto error;
-+
-+    if (strncmp(section, AUDIOGROUP_START, strlen(AUDIOGROUP_START)) == 0) {
-+        char *ag_name = section + strlen(AUDIOGROUP_START);
-+        struct audio_group *ag = (struct audio_group *) pa_hashmap_get(u->unused_audio_groups, ag_name);
-+
-+        if (!ag) {
-+            /* first item for this audio group section, so create the struct */
-+            ag = audio_group_new(u, ag_name);
-+            pa_hashmap_put(u->unused_audio_groups, ag->id, ag);
-+        }
-+
-+        if (strcmp(state->lvalue, "description") == 0)
-+            audio_group_set_description(ag, state->rvalue);
-+
-+        else if (strcmp(state->lvalue, "volume-control") == 0) {
-+            if (pa_streq(state->rvalue, "create"))
-+                audio_group_set_volume_control_action(ag, CONTROL_ACTION_CREATE, NULL);
-+
-+            else if (pa_streq(state->rvalue, NONE_KEYWORD))
-+                audio_group_set_volume_control_action(ag, CONTROL_ACTION_NONE, NULL);
-+
-+            else if (pa_startswith(state->rvalue, BIND_KEYWORD)) {
-+                r = pa_binding_target_info_new_from_string(state->rvalue, "volume_control", &target_info);
-+                if (r < 0) {
-+                    pa_log("[%s:%u] Failed to parse binding target \"%s\".", state->filename, state->lineno, state->rvalue);
-+                    goto error;
-+                }
-+
-+                audio_group_set_volume_control_action(ag, CONTROL_ACTION_BIND, target_info);
-+                pa_binding_target_info_free(target_info);
-+
-+            } else {
-+                pa_log("[%s:%u] Failed to parse value \"%s\".", state->filename, state->lineno, state->rvalue);
-+                goto error;
-+            }
-+        }
-+        else if (strcmp(state->lvalue, "mute-control") == 0) {
-+            if (pa_streq(state->rvalue, "create"))
-+                audio_group_set_mute_control_action(ag, CONTROL_ACTION_CREATE, NULL);
-+
-+            else if (pa_streq(state->rvalue, NONE_KEYWORD))
-+                audio_group_set_mute_control_action(ag, CONTROL_ACTION_NONE, NULL);
-+
-+            else if (pa_startswith(state->rvalue, BIND_KEYWORD)) {
-+                r = pa_binding_target_info_new_from_string(state->rvalue, "mute_control", &target_info);
-+                if (r < 0) {
-+                    pa_log("[%s:%u] Failed to parse binding target \"%s\".", state->filename, state->lineno, state->rvalue);
-+                    goto error;
-+                }
-+
-+                audio_group_set_mute_control_action(ag, CONTROL_ACTION_BIND, target_info);
-+                pa_binding_target_info_free(target_info);
-+
-+            } else {
-+                pa_log("[%s:%u] Failed to parse value \"%s\".", state->filename, state->lineno, state->rvalue);
-+                goto error;
-+            }
-+        }
-+    }
-+    else if (strncmp(section, STREAM_START, strlen(STREAM_START)) == 0) {
-+        char *stream_name = section + strlen(STREAM_START);
-+
-+        struct stream *stream = (struct stream *) pa_hashmap_get(u->unused_streams, stream_name);
-+
-+        if (!stream) {
-+            /* first item for this stream section, so create the struct */
-+            stream = stream_new(u, stream_name);
-+            pa_hashmap_put(u->unused_streams, stream->id, stream);
-+        }
-+
-+        if (pa_streq(state->lvalue, "audio-group-for-volume"))
-+            stream_set_audio_group_name_for_volume(stream, *state->rvalue ? state->rvalue : NULL);
-+
-+        else if (pa_streq(state->lvalue, "audio-group-for-mute"))
-+            stream_set_audio_group_name_for_mute(stream, *state->rvalue ? state->rvalue : NULL);
-+
-+        else if (strcmp(state->lvalue, "match") == 0) {
-+            if (!state->rvalue)
-+                goto error;
-+
-+            stream->rule = parse_rule(state->rvalue);
-+
-+            if (!stream->rule) {
-+                goto error;
-+            }
-+        }
-+    }
-+
-+    return 0;
-+
-+error:
-+
-+    pa_log_error("failed parsing audio group definition file");
-+    return -1;
-+
-+#undef NONE_KEYWORD
-+#undef AUDIO_GROUP_KEYWORD
-+#undef BIND_KEYWORD
-+#undef STREAM_START
-+#undef AUDIOGROUP_START
-+}
-+
-+static void finalize_config(struct userdata *u) {
-+    const char *group_name;
-+    void *state;
-+    struct audio_group *group;
-+    const char *stream_name;
-+    unsigned idx;
-+    struct stream *stream;
-+
-+    pa_assert(u);
-+
-+    PA_HASHMAP_FOREACH(group_name, u->audio_group_names, state) {
-+        int r;
-+
-+        group = pa_hashmap_remove(u->unused_audio_groups, group_name);
-+        if (!group)
-+            group = audio_group_new(u, group_name);
-+
-+        r = audio_group_put(group);
-+        if (r < 0) {
-+            pa_log("Failed to create audio group %s.", group_name);
-+            audio_group_free(group);
-+            continue;
-+        }
-+
-+        pa_assert_se(pa_hashmap_put(u->audio_groups, group->id, group) >= 0);
-+    }
-+
-+    PA_HASHMAP_FOREACH(group, u->unused_audio_groups, state)
-+        pa_log_debug("Audio group %s is not used.", group->id);
-+
-+    pa_hashmap_free(u->unused_audio_groups);
-+    u->unused_audio_groups = NULL;
-+
-+    pa_hashmap_free(u->audio_group_names);
-+    u->audio_group_names = NULL;
-+
-+    PA_DYNARRAY_FOREACH(stream_name, u->stream_names, idx) {
-+        stream = pa_hashmap_remove(u->unused_streams, stream_name);
-+        if (!stream) {
-+            pa_log("Reference to undefined stream %s, ignoring.", stream_name);
-+            continue;
-+        }
-+
-+        stream_put(stream);
-+        pa_dynarray_append(u->streams, stream);
-+    }
-+
-+    PA_HASHMAP_FOREACH(stream, u->unused_streams, state)
-+        pa_log_debug("Stream %s is not used.", stream->id);
-+
-+    pa_hashmap_free(u->unused_streams);
-+    u->unused_streams = NULL;
-+
-+    pa_dynarray_free(u->stream_names);
-+    u->stream_names = NULL;
-+}
-+
-+static bool parse_configuration(struct userdata *u, const char *filename) {
-+    FILE *f;
-+    char *fn = NULL;
-+
-+    pa_config_item table[] = {
-+        { "audio-groups", parse_audio_groups, NULL, "General" },
-+        { "streams", parse_streams, NULL, "General" },
-+        { NULL, parse_common, NULL, NULL },
-+        { NULL, NULL, NULL, NULL },
-+    };
-+
-+    u->audio_group_names = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
-+    u->unused_audio_groups = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
-+                                                 (pa_free_cb_t) audio_group_free);
-+    u->stream_names = pa_dynarray_new(pa_xfree);
-+    u->unused_streams = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
-+                                            (pa_free_cb_t) stream_free);
-+
-+    if (pa_is_path_absolute(filename))
-+        f = pa_open_config_file(filename, NULL, NULL, &fn);
-+    else {
-+        char *sys_conf_file;
-+
-+        sys_conf_file = pa_sprintf_malloc(PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "%s", filename);
-+        f = pa_open_config_file(sys_conf_file, filename, NULL, &fn);
-+        pa_xfree(sys_conf_file);
-+    }
-+
-+    if (f) {
-+        pa_config_parse(fn, f, table, NULL, u);
-+        pa_xfree(fn);
-+        fn = NULL;
-+        fclose(f);
-+        f = NULL;
-+    }
-+
-+    finalize_config(u);
-+
-+    return true;
-+}
-+
-+void pa__done(pa_module *m) {
-+    struct userdata* u;
-+
-+    pa_assert(m);
-+
-+    u = (struct userdata *) m->userdata;
-+
-+    if (!u)
-+        return;
-+
-+    if (u->new_stream_volume)
-+        pa_hook_slot_free(u->new_stream_volume);
-+
-+    if (u->new_stream_mute)
-+        pa_hook_slot_free(u->new_stream_mute);
-+
-+    if (u->streams)
-+        pa_dynarray_free(u->streams);
-+
-+    if (u->audio_groups)
-+        pa_hashmap_free(u->audio_groups);
-+
-+    if (u->api)
-+        pa_volume_api_unref(u->api);
-+
-+    pa_xfree(u);
-+}
-+
-+int pa__init(pa_module *m) {
-+    pa_modargs *ma = NULL;
-+    struct userdata *u;
-+    const char *filename;
-+
-+    pa_assert(m);
-+
-+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-+        pa_log("Failed to parse module arguments");
-+        goto error;
-+    }
-+
-+    u = m->userdata = pa_xnew0(struct userdata, 1);
-+
-+    if (!u)
-+        goto error;
-+
-+    u->api = pa_volume_api_get(m->core);
-+
-+    if (!u->api)
-+        goto error;
-+
-+    u->audio_groups = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
-+                                          (pa_free_cb_t) audio_group_free);
-+    u->streams = pa_dynarray_new((pa_free_cb_t) stream_free);
-+
-+    filename = pa_modargs_get_value(ma, "filename", AUDIO_GROUP_CONFIG);
-+
-+    if (!parse_configuration(u, filename))
-+        goto error;
-+
-+    u->new_stream_volume = pa_hook_connect(&u->api->hooks[PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_VOLUME_CONTROL], PA_HOOK_EARLY, (pa_hook_cb_t) set_volume_control_cb, u);
-+    u->new_stream_mute = pa_hook_connect(&u->api->hooks[PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_MUTE_CONTROL], PA_HOOK_EARLY, (pa_hook_cb_t) set_mute_control_cb, u);
-+
-+    if (!u->new_stream_volume || !u->new_stream_mute)
-+        goto error;
-+
-+    pa_modargs_free(ma);
-+
-+    return 0;
-+
-+error:
-+    pa__done(m);
-+
-+    if (ma)
-+        pa_modargs_free(ma);
-+
-+    return -1;
-+}
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0082-Add-module-main-volume-policy.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0082-Add-module-main-volume-policy.patch
deleted file mode 100644 (file)
index 52fd3ab..0000000
+++ /dev/null
@@ -1,1404 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Wed, 21 May 2014 14:13:41 +0300
-Subject: 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
-+++ b/Makefile.am
-@@ -61,6 +61,9 @@ moduledevinternaldir   = $(includedir)/pulsemodule/pulse
- moduledevvolumeapi_DATA = src/modules/volume-api/*.h
- moduledevvolumeapidir   = $(includedir)/pulsemodule/modules/volume-api
-+moduledevmainvolumepolicy_DATA = src/modules/main-volume-policy/*.h
-+moduledevmainvolumepolicydir   = $(includedir)/pulsemodule/modules/main-volume-policy
-+
- filterdir = /etc/pulse/filter
- filter_DATA = filter/filter_44100_48000.dat \
-             filter/filter_44100_8000.dat \
-diff --git a/src/Makefile.am b/src/Makefile.am
-index a6bb319..8fa60ec 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -1017,6 +1017,7 @@ libpulsecore_foreign_la_CFLAGS = $(AM_CFLAGS) $(FOREIGN_CFLAGS)
- modlibexec_LTLIBRARIES = \
-               libcli.la \
-+              libmain-volume-policy.la \
-               libprotocol-cli.la \
-               libprotocol-simple.la \
-               libprotocol-http.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
-@@ -1133,6 +1140,7 @@ endif
- modlibexec_LTLIBRARIES += \
-               module-cli.la \
-               module-cli-protocol-tcp.la \
-+              module-main-volume-policy.la \
-               module-simple-protocol-tcp.la \
-               module-volume-api.la \
-               module-null-sink.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
-@@ -197,6 +197,10 @@ load-module module-volume-api
- load-module module-audio-groups
- .endif
-+.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);
-+}
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0083-configuration-Add-default-IVI-audio-group-and-main-v.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0083-configuration-Add-default-IVI-audio-group-and-main-v.patch
deleted file mode 100644 (file)
index 5eed75c..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Thu, 22 May 2014 14:43:33 +0300
-Subject: configuration: Add default IVI audio group and main volume
- configuration
-
-Change-Id: Idd348cc9f469e988405d574dbc2459c5822a33c2
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/Makefile.am                                | 21 ++++++++++++++++
- src/tizen-ivi-examples/audio-groups.conf       | 33 ++++++++++++++++++++++++++
- src/tizen-ivi-examples/main-volume-policy.conf | 20 ++++++++++++++++
- 3 files changed, 74 insertions(+)
- create mode 100644 src/tizen-ivi-examples/audio-groups.conf
- create mode 100644 src/tizen-ivi-examples/main-volume-policy.conf
-
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 8fa60ec..d57c30b 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -89,6 +89,8 @@ MODULE_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_
- EXTRA_DIST = \
-               pulse/client.conf.in \
-               pulse/version.h.in \
-+              tizen-ivi-examples/audio-groups.conf \
-+              tizen-ivi-examples/main-volume-policy.conf \
-               daemon/daemon.conf.in \
-               daemon/default.pa.in \
-               daemon/system.pa.in \
-@@ -111,6 +113,25 @@ pulseconf_DATA = \
-               daemon.conf \
-               client.conf
-+# Add some Tizen specific configuration files.
-+#
-+# FIXME: These configuration files should be installed only if explicitly
-+# requested, because they define policy which may not be the desired policy in
-+# every Tizen profile. Currently default.pa loads module-audio-groups and
-+# module-main-volume-policy only if module-murphy-ivi is installed in the
-+# system, which helps with this issue, because non-IVI profiles don't
-+# currently use module-murphy-ivi, so these configuration files won't have any
-+# effect outside the IVI profile, but this is pretty hacky solution. It would
-+# be better to load module-audio-groups and module-main-volume-policy
-+# unconditionally, since they're not really tied to the Murphy module in any
-+# way. We use this hack, because otherwise we'd need a configure switch for
-+# enabling the example IVI configuration, and a new configure switch would also
-+# require a new switch in the Tizen IVI image configuration. That's an extra
-+# hurdle that we decided to avoid for now.
-+pulseconf_DATA += \
-+              tizen-ivi-examples/audio-groups.conf \
-+              tizen-ivi-examples/main-volume-policy.conf
-+
- if HAVE_DBUS
- dbuspolicy_DATA = \
-               daemon/pulseaudio-system.conf
-diff --git a/src/tizen-ivi-examples/audio-groups.conf b/src/tizen-ivi-examples/audio-groups.conf
-new file mode 100644
-index 0000000..54939c9
---- /dev/null
-+++ b/src/tizen-ivi-examples/audio-groups.conf
-@@ -0,0 +1,33 @@
-+[General]
-+audio-groups = x-example-call-downlink-audio-group x-example-navigator-output-audio-group x-example-default-output-audio-group
-+streams = call-downlink navigator-output default-output
-+
-+[AudioGroup x-example-call-downlink-audio-group]
-+description = Call downlink
-+volume-control = create
-+mute-control = create
-+
-+[AudioGroup x-example-navigator-output-audio-group]
-+description = Navigator
-+volume-control = create
-+mute-control = create
-+
-+[AudioGroup x-example-default-output-audio-group]
-+description = Default
-+volume-control = create
-+mute-control = create
-+
-+[Stream call-downlink]
-+match = (direction output AND property media.role=phone)
-+audio-group-for-volume = x-example-call-downlink-audio-group
-+audio-group-for-mute = x-example-call-downlink-audio-group
-+
-+[Stream navigator-output]
-+match = (direction output AND property media.role=navigator)
-+audio-group-for-volume = x-example-navigator-output-audio-group
-+audio-group-for-mute = x-example-navigator-output-audio-group
-+
-+[Stream default-output]
-+match = (direction output)
-+audio-group-for-volume = x-example-default-output-audio-group
-+audio-group-for-mute = x-example-default-output-audio-group
-diff --git a/src/tizen-ivi-examples/main-volume-policy.conf b/src/tizen-ivi-examples/main-volume-policy.conf
-new file mode 100644
-index 0000000..5a73308
---- /dev/null
-+++ b/src/tizen-ivi-examples/main-volume-policy.conf
-@@ -0,0 +1,20 @@
-+[General]
-+output-volume-model = by-active-main-volume-context
-+input-volume-model = none
-+output-mute-model = by-active-main-volume-context
-+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 = none
-+main-output-mute-control = bind:AudioGroup:x-example-call-downlink-audio-group
-+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 = none
-+main-output-mute-control = bind:AudioGroup:x-example-default-output-audio-group
-+main-input-mute-control = none
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0084-sink-source-Initialize-port-before-fixate-hook-fixes.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0084-sink-source-Initialize-port-before-fixate-hook-fixes.patch
deleted file mode 100644 (file)
index 37b4f85..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-From: David Henningsson <david.henningsson@canonical.com>
-Date: Fri, 21 Mar 2014 10:19:19 +0100
-Subject: sink/source: Initialize port before fixate hook (fixes volume/mute
- not saved)
-
-In case a port has not yet been saved, which is e g often the case
-if a sink/source has only one port, reading volume/mute will be done
-without port, whereas writing volume/mute will be done with port.
-
-Work around this by setting a default port before the fixate hook,
-so module-device-restore can read volume/mute for the correct port.
-
-Change-Id: Iea6a742f0667771712059cb39b8082785b2a6887
-BugLink: https://bugs.launchpad.net/bugs/1289515
-Signed-off-by: David Henningsson <david.henningsson@canonical.com>
----
- src/pulsecore/device-port.c | 27 +++++++++++++++++++++++++++
- src/pulsecore/device-port.h |  2 ++
- src/pulsecore/sink.c        | 27 ++++++++++-----------------
- src/pulsecore/source.c      | 28 ++++++++++------------------
- 4 files changed, 49 insertions(+), 35 deletions(-)
-
-diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c
-index c183990..1520142 100644
---- a/src/pulsecore/device-port.c
-+++ b/src/pulsecore/device-port.c
-@@ -191,3 +191,30 @@ void pa_device_port_active_changed(pa_device_port *port, bool 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;
-+    pa_device_port *p, *best = NULL;
-+
-+    if (!ports)
-+        return NULL;
-+
-+    /* First run: skip unavailable ports */
-+    PA_HASHMAP_FOREACH(p, ports, state) {
-+        if (p->available == PA_AVAILABLE_NO)
-+            continue;
-+
-+        if (!best || p->priority > best->priority)
-+            best = p;
-+    }
-+
-+    /* Second run: if only unavailable ports exist, still suggest a port */
-+    if (!best) {
-+        PA_HASHMAP_FOREACH(p, ports, state)
-+            if (!best || p->priority > best->priority)
-+                best = p;
-+    }
-+
-+    return best;
-+}
-diff --git a/src/pulsecore/device-port.h b/src/pulsecore/device-port.h
-index 2964900..bf45ab9 100644
---- a/src/pulsecore/device-port.h
-+++ b/src/pulsecore/device-port.h
-@@ -87,4 +87,6 @@ void pa_device_port_set_latency_offset(pa_device_port *p, int64_t offset);
- /* Called from sink.c and source.c only. */
- void pa_device_port_active_changed(pa_device_port *port, bool new_active);
-+pa_device_port *pa_device_port_find_best(pa_hashmap *ports);
-+
- #endif
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index 191b560..41cffcc 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -235,6 +235,12 @@ pa_sink* pa_sink_new(
-     pa_device_init_icon(data->proplist, true);
-     pa_device_init_intended_roles(data->proplist);
-+    if (!data->active_port) {
-+        pa_device_port *p = pa_device_port_find_best(data->ports);
-+        if (p)
-+            pa_sink_new_data_set_port(data, p->name);
-+    }
-+
-     if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_FIXATE], data) < 0) {
-         pa_xfree(s);
-         pa_namereg_unregister(core, name);
-@@ -300,23 +306,10 @@ pa_sink* pa_sink_new(
-         if ((s->active_port = pa_hashmap_get(s->ports, data->active_port)))
-             s->save_port = data->save_port;
--    if (!s->active_port) {
--        void *state;
--        pa_device_port *p;
--
--        PA_HASHMAP_FOREACH(p, s->ports, state) {
--            if (p->available == PA_AVAILABLE_NO)
--                continue;
--
--            if (!s->active_port || p->priority > s->active_port->priority)
--                s->active_port = p;
--        }
--        if (!s->active_port) {
--            PA_HASHMAP_FOREACH(p, s->ports, state)
--                if (!s->active_port || p->priority > s->active_port->priority)
--                    s->active_port = p;
--        }
--    }
-+    /* Hopefully the active port has already been assigned in the previous call
-+       to pa_device_port_find_best, but better safe than sorry */
-+    if (!s->active_port)
-+        s->active_port = pa_device_port_find_best(s->ports);
-     if (s->active_port)
-         s->latency_offset = s->active_port->latency_offset;
-diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
-index 0fddfaa..db7f667 100644
---- a/src/pulsecore/source.c
-+++ b/src/pulsecore/source.c
-@@ -222,6 +222,12 @@ pa_source* pa_source_new(
-     pa_device_init_icon(data->proplist, false);
-     pa_device_init_intended_roles(data->proplist);
-+    if (!data->active_port) {
-+        pa_device_port *p = pa_device_port_find_best(data->ports);
-+        if (p)
-+            pa_source_new_data_set_port(data, p->name);
-+    }
-+
-     if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
-         pa_xfree(s);
-         pa_namereg_unregister(core, name);
-@@ -288,24 +294,10 @@ pa_source* pa_source_new(
-         if ((s->active_port = pa_hashmap_get(s->ports, data->active_port)))
-             s->save_port = data->save_port;
--    if (!s->active_port) {
--        void *state;
--        pa_device_port *p;
--
--        PA_HASHMAP_FOREACH(p, s->ports, state) {
--            if (p->available == PA_AVAILABLE_NO)
--                continue;
--
--            if (!s->active_port || p->priority > s->active_port->priority)
--                s->active_port = p;
--        }
--
--        if (!s->active_port) {
--            PA_HASHMAP_FOREACH(p, s->ports, state)
--                if (!s->active_port || p->priority > s->active_port->priority)
--                    s->active_port = p;
--        }
--    }
-+    /* Hopefully the active port has already been assigned in the previous call
-+       to pa_device_port_find_best, but better safe than sorry */
-+    if (!s->active_port)
-+        s->active_port = pa_device_port_find_best(s->ports);
-     if (s->active_port)
-         s->latency_offset = s->active_port->latency_offset;
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0085-configuration-pulseaudio-tizen-configuration-in-defa.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0085-configuration-pulseaudio-tizen-configuration-in-defa.patch
deleted file mode 100644 (file)
index 8a27990..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-From: Jaska Uimonen <jaska.uimonen@intel.com>
-Date: Thu, 18 Jul 2013 18:43:14 +0800
-Subject: configuration: pulseaudio tizen configuration in default.pa
-
-Change-Id: Id9370a1858d5c1ba0ed3319d717bc7f3e9ed5d31
-Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com>
----
- src/daemon/default.pa.in | 60 ++++++++++++++++++++++++------------------------
- 1 file changed, 30 insertions(+), 30 deletions(-)
-
-diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
-index f70804c..bae1a77 100755
---- a/src/daemon/default.pa.in
-+++ b/src/daemon/default.pa.in
-@@ -35,18 +35,6 @@ load-sample-dir-lazy %WINDIR%\Media\*.wav
- .fail
--### Automatically restore the volume of streams and devices
--load-module module-device-restore
--load-module module-stream-restore
--load-module module-card-restore
--
--### Automatically augment property information from .desktop files
--### stored in /usr/share/application
--load-module module-augment-properties
--
--### Should be after module-*-restore but before module-*-detect
--load-module module-switch-on-port-available
--
- ### Load audio drivers statically
- ### (it's probably better to not load these drivers manually, but instead
- ### use module-udev-detect -- see below -- for doing this automatically)
-@@ -81,16 +69,12 @@ load-module module-detect
- ### Automatically connect sink and source if JACK server is present
- .ifexists module-jackdbus-detect@PA_SOEXT@
- .nofail
--load-module module-jackdbus-detect channels=2
-+load-module module-jackdbus-detect
- .fail
- .endif
- ifelse(@HAVE_BLUEZ@, 1, [dnl
- ### Automatically load driver modules for Bluetooth hardware
--.ifexists module-bluetooth-policy@PA_SOEXT@
--load-module module-bluetooth-policy
--.endif
--
- .ifexists module-bluetooth-discover@PA_SOEXT@
- load-module module-bluetooth-discover
- .endif
-@@ -142,9 +126,6 @@ load-module module-rescue-streams
- ### Make sure we always have a sink around, even if it is a null sink.
- load-module module-always-sink
--### Honour intended role device property
--load-module module-intended-roles
--
- ### Automatically suspend sinks/sources that become idle for too long
- load-module module-suspend-on-idle
-@@ -160,15 +141,16 @@ load-module module-systemd-login
- ### Enable positioned event sounds
- load-module module-position-event-sounds
--### Cork music/video streams when a phone stream is active
--load-module module-role-cork
--
- ### Modules to allow autoloading of filters (such as echo cancellation)
- ### on demand. module-filter-heuristics tries to determine what filters
- ### make sense, and module-filter-apply does the heavy-lifting of
- ### loading modules and rerouting streams.
-+.ifexists module-filter-heuristics@PA_SOEXT@
- load-module module-filter-heuristics
-+.endif
-+.ifexists module-filter-apply@PA_SOEXT@
- load-module module-filter-apply
-+.endif
- ])dnl
- ifelse(@HAVE_X11@, 1, [dnl
-@@ -189,16 +171,34 @@ ifelse(@HAVE_X11@, 1, [dnl
- #.endif
- ])dnl
--.ifexists module-volume-api
-+### Load the Murphy IVI module if it exists
-+.ifexists module-murphy-ivi@PA_SOEXT@
-+load-module module-murphy-ivi
-+load-module module-stream-restore restore_device=false on_hotplug=false on_rescue=false restore_volume=true preferred_stream_group=media.role.within.application.name
-+load-module module-native-protocol-tcp
- load-module module-volume-api
--.endif
--
--.ifexists module-audio-groups
- load-module module-audio-groups
--.endif
--
--.ifexists module-main-volume-policy
- load-module module-main-volume-policy
-+.else
-+### Automatically restore the volume of streams and devices
-+load-module module-device-restore
-+load-module module-stream-restore
-+load-module module-card-restore
-+
-+### Automatically augment property information from .desktop files
-+### stored in /usr/share/application
-+.nofail
-+load-module module-augment-properties
-+.fail
-+
-+### Honour intended role device property
-+load-module module-intended-roles
-+
-+### Cork music/video streams when a phone stream is active
-+load-module module-role-cork
-+
-+load-module module-switch-on-port-available
-+
- .endif
- ### Make some devices default
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0086-pactl-Fix-crash-in-pactl-list.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0086-pactl-Fix-crash-in-pactl-list.patch
deleted file mode 100644 (file)
index e817684..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 26 May 2014 16:26:14 +0300
-Subject: pactl: Fix crash in "pactl list"
-
-Fixes this assertion error:
-
-Assertion 'actions > 0' failed at utils/pactl.c:172, function complete_action(). Aborting.
-
-Change-Id: Icdcdf0817af431115444cb4fdef0a042fe5d7560
----
- src/utils/pactl.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/utils/pactl.c b/src/utils/pactl.c
-index f947681..d8921f1 100644
---- a/src/utils/pactl.c
-+++ b/src/utils/pactl.c
-@@ -1673,7 +1673,7 @@ static void volume_api_state_cb(pa_context *c, void *userdata) {
-                         o = pa_ext_volume_api_get_audio_group_info_list(c, get_audio_group_info_callback, NULL);
-                         pa_operation_unref(o);
-                         o = NULL;
--                        actions += 4;
-+                        actions += 5;
-                     } else if (pa_streq(list_type, "volume-controls")) {
-                         o = pa_ext_volume_api_get_volume_control_info_list(c, get_volume_control_info_callback, NULL);
-                         actions++;
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0087-configuration-x-example-x-tizen-ivi-in-volume-config.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0087-configuration-x-example-x-tizen-ivi-in-volume-config.patch
deleted file mode 100644 (file)
index 2882e56..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-From: Ismo Puustinen <ismo.puustinen@intel.com>
-Date: Mon, 26 May 2014 14:37:48 +0300
-Subject: configuration: x-example -> x-tizen-ivi in volume configuration.
-
-Change-Id: I1c11084d6891e431dd909c632e4bfb62968167df
----
- src/Makefile.am                                |  8 +++----
- src/tizen-ivi-examples/audio-groups.conf       | 33 --------------------------
- src/tizen-ivi-examples/main-volume-policy.conf | 20 ----------------
- src/tizen-ivi/audio-groups.conf                | 33 ++++++++++++++++++++++++++
- src/tizen-ivi/main-volume-policy.conf          | 20 ++++++++++++++++
- 5 files changed, 57 insertions(+), 57 deletions(-)
- delete mode 100644 src/tizen-ivi-examples/audio-groups.conf
- delete mode 100644 src/tizen-ivi-examples/main-volume-policy.conf
- create mode 100644 src/tizen-ivi/audio-groups.conf
- create mode 100644 src/tizen-ivi/main-volume-policy.conf
-
-diff --git a/src/Makefile.am b/src/Makefile.am
-index d57c30b..9d17336 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -89,8 +89,8 @@ MODULE_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_
- EXTRA_DIST = \
-               pulse/client.conf.in \
-               pulse/version.h.in \
--              tizen-ivi-examples/audio-groups.conf \
--              tizen-ivi-examples/main-volume-policy.conf \
-+              tizen-ivi/audio-groups.conf \
-+              tizen-ivi/main-volume-policy.conf \
-               daemon/daemon.conf.in \
-               daemon/default.pa.in \
-               daemon/system.pa.in \
-@@ -129,8 +129,8 @@ pulseconf_DATA = \
- # require a new switch in the Tizen IVI image configuration. That's an extra
- # hurdle that we decided to avoid for now.
- pulseconf_DATA += \
--              tizen-ivi-examples/audio-groups.conf \
--              tizen-ivi-examples/main-volume-policy.conf
-+              tizen-ivi/audio-groups.conf \
-+              tizen-ivi/main-volume-policy.conf
- if HAVE_DBUS
- dbuspolicy_DATA = \
-diff --git a/src/tizen-ivi-examples/audio-groups.conf b/src/tizen-ivi-examples/audio-groups.conf
-deleted file mode 100644
-index 54939c9..0000000
---- a/src/tizen-ivi-examples/audio-groups.conf
-+++ /dev/null
-@@ -1,33 +0,0 @@
--[General]
--audio-groups = x-example-call-downlink-audio-group x-example-navigator-output-audio-group x-example-default-output-audio-group
--streams = call-downlink navigator-output default-output
--
--[AudioGroup x-example-call-downlink-audio-group]
--description = Call downlink
--volume-control = create
--mute-control = create
--
--[AudioGroup x-example-navigator-output-audio-group]
--description = Navigator
--volume-control = create
--mute-control = create
--
--[AudioGroup x-example-default-output-audio-group]
--description = Default
--volume-control = create
--mute-control = create
--
--[Stream call-downlink]
--match = (direction output AND property media.role=phone)
--audio-group-for-volume = x-example-call-downlink-audio-group
--audio-group-for-mute = x-example-call-downlink-audio-group
--
--[Stream navigator-output]
--match = (direction output AND property media.role=navigator)
--audio-group-for-volume = x-example-navigator-output-audio-group
--audio-group-for-mute = x-example-navigator-output-audio-group
--
--[Stream default-output]
--match = (direction output)
--audio-group-for-volume = x-example-default-output-audio-group
--audio-group-for-mute = x-example-default-output-audio-group
-diff --git a/src/tizen-ivi-examples/main-volume-policy.conf b/src/tizen-ivi-examples/main-volume-policy.conf
-deleted file mode 100644
-index 5a73308..0000000
---- a/src/tizen-ivi-examples/main-volume-policy.conf
-+++ /dev/null
-@@ -1,20 +0,0 @@
--[General]
--output-volume-model = by-active-main-volume-context
--input-volume-model = none
--output-mute-model = by-active-main-volume-context
--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 = none
--main-output-mute-control = bind:AudioGroup:x-example-call-downlink-audio-group
--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 = none
--main-output-mute-control = bind:AudioGroup:x-example-default-output-audio-group
--main-input-mute-control = none
-diff --git a/src/tizen-ivi/audio-groups.conf b/src/tizen-ivi/audio-groups.conf
-new file mode 100644
-index 0000000..4839307
---- /dev/null
-+++ b/src/tizen-ivi/audio-groups.conf
-@@ -0,0 +1,33 @@
-+[General]
-+audio-groups = x-tizen-ivi-call-downlink-audio-group x-tizen-ivi-navigator-output-audio-group x-tizen-ivi-default-output-audio-group
-+streams = call-downlink navigator-output default-output
-+
-+[AudioGroup x-tizen-ivi-call-downlink-audio-group]
-+description = Call downlink
-+volume-control = create
-+mute-control = create
-+
-+[AudioGroup x-tizen-ivi-navigator-output-audio-group]
-+description = Navigator
-+volume-control = create
-+mute-control = create
-+
-+[AudioGroup x-tizen-ivi-default-output-audio-group]
-+description = Default
-+volume-control = create
-+mute-control = create
-+
-+[Stream call-downlink]
-+match = (direction output AND property media.role=phone)
-+audio-group-for-volume = x-tizen-ivi-call-downlink-audio-group
-+audio-group-for-mute = x-tizen-ivi-call-downlink-audio-group
-+
-+[Stream navigator-output]
-+match = (direction output AND property media.role=navigator)
-+audio-group-for-volume = x-tizen-ivi-navigator-output-audio-group
-+audio-group-for-mute = x-tizen-ivi-navigator-output-audio-group
-+
-+[Stream default-output]
-+match = (direction output)
-+audio-group-for-volume = x-tizen-ivi-default-output-audio-group
-+audio-group-for-mute = x-tizen-ivi-default-output-audio-group
-diff --git a/src/tizen-ivi/main-volume-policy.conf b/src/tizen-ivi/main-volume-policy.conf
-new file mode 100644
-index 0000000..0a83968
---- /dev/null
-+++ b/src/tizen-ivi/main-volume-policy.conf
-@@ -0,0 +1,20 @@
-+[General]
-+output-volume-model = by-active-main-volume-context
-+input-volume-model = none
-+output-mute-model = by-active-main-volume-context
-+input-mute-model = none
-+main-volume-contexts = x-tizen-ivi-call default
-+
-+[MainVolumeContext x-tizen-ivi-call]
-+description = Call main volume context
-+main-output-volume-control = bind:AudioGroup:x-tizen-ivi-call-downlink-audio-group
-+main-input-volume-control = none
-+main-output-mute-control = bind:AudioGroup:x-tizen-ivi-call-downlink-audio-group
-+main-input-mute-control = none
-+
-+[MainVolumeContext default]
-+description = Default main volume context
-+main-output-volume-control = bind:AudioGroup:x-tizen-ivi-default-output-audio-group
-+main-input-volume-control = none
-+main-output-mute-control = bind:AudioGroup:x-tizen-ivi-default-output-audio-group
-+main-input-mute-control = none
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0088-device-creator-stream-creator-Add-a-couple-of-assert.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0088-device-creator-stream-creator-Add-a-couple-of-assert.patch
deleted file mode 100644 (file)
index a637c29..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Tue, 27 May 2014 10:45:04 +0300
-Subject: device-creator, stream-creator: Add a couple of assertions
-
-Klocwork complained that source (in device-creator) and output (in
-stream-creator) may be dereferenced if they're NULL. Let's make
-Klocwork happy, and the code a bit more obvious to human readers as
-well.
-
-Change-Id: I835dd7d9da44e2866a97bc0424001a42c29602a8
----
- src/modules/volume-api/device-creator.c | 4 +++-
- src/modules/volume-api/stream-creator.c | 4 +++-
- 2 files changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/src/modules/volume-api/device-creator.c b/src/modules/volume-api/device-creator.c
-index 1d912ba..f35fab0 100644
---- a/src/modules/volume-api/device-creator.c
-+++ b/src/modules/volume-api/device-creator.c
-@@ -513,8 +513,10 @@ static pa_hook_result_t sink_or_source_mute_changed_cb(void *hook_data, void *ca
-     if (sink)
-         mute = sink->muted;
--    else
-+    else if (source)
-         mute = source->muted;
-+    else
-+        pa_assert_not_reached();
-     pa_mute_control_mute_changed(control->mute_control, mute);
-diff --git a/src/modules/volume-api/stream-creator.c b/src/modules/volume-api/stream-creator.c
-index 2bd0053..f6ca7b3 100644
---- a/src/modules/volume-api/stream-creator.c
-+++ b/src/modules/volume-api/stream-creator.c
-@@ -216,8 +216,10 @@ static pa_hook_result_t sink_input_or_source_output_mute_changed_cb(void *hook_d
-     if (input)
-         mute = input->muted;
--    else
-+    else if (output)
-         mute = output->muted;
-+    else
-+        pa_assert_not_reached();
-     pa_mute_control_mute_changed(stream->stream->own_mute_control, mute);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0089-main-volume-policy-Fix-a-memory-leak.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0089-main-volume-policy-Fix-a-memory-leak.patch
deleted file mode 100644 (file)
index 8c46a1b..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Tue, 27 May 2014 11:06:10 +0300
-Subject: main-volume-policy: Fix a memory leak
-
-There can be multiple calls to pa_binding_target_info_new() in this
-function, but only the last allocated info object was freed.
-
-Change-Id: I9df43f0663b27b07ba7b8d01bc8ea9cc0a6c1b51
----
- src/modules/main-volume-policy/module-main-volume-policy.c | 9 +++++----
- 1 file changed, 5 insertions(+), 4 deletions(-)
-
-diff --git a/src/modules/main-volume-policy/module-main-volume-policy.c b/src/modules/main-volume-policy/module-main-volume-policy.c
-index a14699d..0a89aa7 100644
---- a/src/modules/main-volume-policy/module-main-volume-policy.c
-+++ b/src/modules/main-volume-policy/module-main-volume-policy.c
-@@ -253,7 +253,7 @@ static pa_hook_result_t active_main_volume_context_changed_cb(void *hook_data, v
-     struct userdata *u = userdata;
-     pa_main_volume_context *context;
-     pa_volume_api *api;
--    pa_binding_target_info *info = NULL;
-+    pa_binding_target_info *info;
-     pa_assert(u);
-@@ -265,6 +265,7 @@ static pa_hook_result_t active_main_volume_context_changed_cb(void *hook_data, v
-             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);
-+            pa_binding_target_info_free(info);
-         } else
-             pa_volume_api_set_main_output_volume_control(api, NULL);
-     }
-@@ -274,6 +275,7 @@ static pa_hook_result_t active_main_volume_context_changed_cb(void *hook_data, v
-             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);
-+            pa_binding_target_info_free(info);
-         } else
-             pa_volume_api_set_main_input_volume_control(api, NULL);
-     }
-@@ -283,6 +285,7 @@ static pa_hook_result_t active_main_volume_context_changed_cb(void *hook_data, v
-             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);
-+            pa_binding_target_info_free(info);
-         } else
-             pa_volume_api_set_main_output_mute_control(api, NULL);
-     }
-@@ -292,13 +295,11 @@ static pa_hook_result_t active_main_volume_context_changed_cb(void *hook_data, v
-             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);
-+            pa_binding_target_info_free(info);
-         } else
-             pa_volume_api_set_main_input_mute_control(api, NULL);
-     }
--    if (info)
--        pa_binding_target_info_free(info);
--
-     return PA_HOOK_OK;
- }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0090-audio-groups-fix-issues-found-by-static-analysis.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0090-audio-groups-fix-issues-found-by-static-analysis.patch
deleted file mode 100644 (file)
index 52bfd20..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-From: Ismo Puustinen <ismo.puustinen@intel.com>
-Date: Tue, 27 May 2014 10:27:16 +0300
-Subject: audio-groups: fix issues found by static analysis.
-
-Change-Id: Ia2805a5977868b236bd6a33e7bc8fdcb944020ea
----
- src/modules/audio-groups/module-audio-groups.c | 63 ++++++++++++++++----------
- 1 file changed, 40 insertions(+), 23 deletions(-)
-
-diff --git a/src/modules/audio-groups/module-audio-groups.c b/src/modules/audio-groups/module-audio-groups.c
-index 320847c..2b3a570 100644
---- a/src/modules/audio-groups/module-audio-groups.c
-+++ b/src/modules/audio-groups/module-audio-groups.c
-@@ -383,9 +383,13 @@ static bool match_predicate(struct literal *l, pas_stream *d) {
-     else if (l->property_name && l->property_value) {
-         /* check the property from the property list */
--        if (pa_proplist_contains(d->proplist, l->property_name) &&
--                strcmp(pa_proplist_gets(d->proplist, l->property_name), l->property_value) == 0)
--            return true;
-+        if (pa_proplist_contains(d->proplist, l->property_name)) {
-+            const char *prop = pa_proplist_gets(d->proplist, l->property_name);
-+
-+            if (prop && strcmp(prop, l->property_value) == 0) {
-+                return true;
-+            }
-+        }
-     }
-     /* no match */
-@@ -631,18 +635,8 @@ static struct expression_token *parse_rule_internal(const char *rule, bool disju
-     char *p;
-     int brace_count = 0;
-     bool braces_present = false;
--    char left_buf[len];
--    char right_buf[len];
--
--#if 0
--    /* check if the rule is still valid */
--
--    if (len < 2)
--        return NULL;
--
--    if (rule[0] != '(' || rule[len-1] != ')')
--        return NULL;
--#endif
-+    char left_buf[len+1];
-+    char right_buf[len+1];
-     et = pa_xnew0(struct expression_token, 1);
-@@ -740,9 +734,9 @@ static struct expression_token *parse_rule_internal(const char *rule, bool disju
-     else {
-         /* this is a literal */
-         char *begin_lit;
--        char buf[strlen(rule)+1];
--
-+        char buf[len+1];
-         struct literal_token *lit = pa_xnew0(struct literal_token, 1);
-+
-         if (!lit) {
-             delete_expression_token(et);
-             return NULL;
-@@ -769,7 +763,8 @@ static struct expression_token *parse_rule_internal(const char *rule, bool disju
-             *l = '\0';
-         }
-         else {
--            strncpy(buf, rule, sizeof(buf));
-+            strncpy(buf, rule, len);
-+            buf[len] = '\0';
-         }
-         if (strncmp(buf, "NEG", 3) == 0) {
-@@ -782,6 +777,7 @@ static struct expression_token *parse_rule_internal(const char *rule, bool disju
-         }
-         lit->var = pa_xstrdup(begin_lit);
-+
-         et->lit = lit;
-     }
-@@ -869,8 +865,9 @@ static bool gather_conjunction(struct expression_token *et, struct conjunction *
-     if (et->oper == operator_and) {
-         if (!gather_conjunction(et->left, c) ||
--            !gather_conjunction(et->right, c))
-+            !gather_conjunction(et->right, c)) {
-             return false;
-+        }
-     }
-     else {
-         /* literal */
-@@ -879,8 +876,13 @@ static bool gather_conjunction(struct expression_token *et, struct conjunction *
-         if (!l)
-             return false;
--        gather_literal(et, l);
-+        if (!gather_literal(et, l)) {
-+            pa_log_error("audio groups config: literal parsing failed");
-+            delete_literal(l);
-+            return false;
-+        }
-+        PA_LLIST_INIT(struct literal, l);
-         PA_LLIST_PREPEND(struct literal, c->literals, l);
-     }
-@@ -897,9 +899,18 @@ static bool gather_expression(struct expression *e, struct expression_token *et)
-     else {
-         /* conjunction or literal */
-         struct conjunction *c = pa_xnew0(struct conjunction, 1);
--        if (!gather_conjunction(et, c))
-+
-+        if (!c)
-             return false;
-+        PA_LLIST_HEAD_INIT(struct literal, c->literals);
-+
-+        if (!gather_conjunction(et, c)) {
-+            delete_conjunction(c);
-+            return false;
-+        }
-+
-+        PA_LLIST_INIT(struct conjunction, c);
-         PA_LLIST_PREPEND(struct conjunction, e->conjunctions, c);
-     }
-@@ -950,10 +961,16 @@ static struct expression *parse_rule(const char *rule_string) {
-     if (!e)
-         goto error;
-+    PA_LLIST_HEAD_INIT(struct conjunction, e->conjunctions);
-+
-     /* gather expressions to actual match format */
--    gather_expression(e, et);
-+    if (!gather_expression(e, et)) {
-+        /* gathering the expression from tokens went wrong */
-+        pa_log_error("failed to parse audio group stream classification data");
-+        goto error;
-+    }
--#if 1
-+#if 0
-     print_expression(e);
- #endif
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0091-core-util-Add-pa_append_to_home_dir.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0091-core-util-Add-pa_append_to_home_dir.patch
deleted file mode 100644 (file)
index 89732c8..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Sun, 8 Jun 2014 16:32:57 +0300
-Subject: core-util: Add pa_append_to_home_dir()
-
-Change-Id: I746d2efb5f205820480b0cbd11c23cff11367656
----
- src/pulsecore/authkey.c   |  7 ++-----
- src/pulsecore/core-util.c | 17 +++++++++++++++++
- src/pulsecore/core-util.h |  1 +
- 3 files changed, 20 insertions(+), 5 deletions(-)
-
-diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c
-index 03c0c4b..be31e98 100644
---- a/src/pulsecore/authkey.c
-+++ b/src/pulsecore/authkey.c
-@@ -156,14 +156,11 @@ static char *normalize_path(const char *fn) {
- #else
-     if (strlen(fn) < 3 || !IsCharAlpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
- #endif
--        char *homedir, *s;
-+        char *s;
--        if (!(homedir = pa_get_home_dir_malloc()))
-+        if (pa_append_to_home_dir(fn, &s) < 0)
-             return NULL;
--        s = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", homedir, fn);
--        pa_xfree(homedir);
--
-         return s;
-     }
-diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
-index 508b3d3..99aa51f 100644
---- a/src/pulsecore/core-util.c
-+++ b/src/pulsecore/core-util.c
-@@ -1685,6 +1685,23 @@ char *pa_get_home_dir_malloc(void) {
-     return homedir;
- }
-+int pa_append_to_home_dir(const char *path, char **_r) {
-+    char *home_dir;
-+
-+    pa_assert(path);
-+    pa_assert(_r);
-+
-+    home_dir = pa_get_home_dir_malloc();
-+    if (!home_dir) {
-+        pa_log("Failed to get home directory.");
-+        return -PA_ERR_NOENTITY;
-+    }
-+
-+    *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", home_dir, path);
-+    pa_xfree(home_dir);
-+    return 0;
-+}
-+
- char *pa_get_binary_name_malloc(void) {
-     char *t;
-     size_t allocated = 128;
-diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
-index aba1863..05d628e 100644
---- a/src/pulsecore/core-util.h
-+++ b/src/pulsecore/core-util.h
-@@ -137,6 +137,7 @@ char* pa_find_config_file(const char *global, const char *local, const char *env
- char *pa_get_runtime_dir(void);
- char *pa_get_state_dir(void);
- char *pa_get_home_dir_malloc(void);
-+int pa_append_to_home_dir(const char *path, char **_r);
- char *pa_get_binary_name_malloc(void);
- char *pa_runtime_path(const char *fn);
- char *pa_state_path(const char *fn, bool prepend_machine_id);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0092-core-util-Add-pa_get_config_home_dir.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0092-core-util-Add-pa_get_config_home_dir.patch
deleted file mode 100644 (file)
index e5e05e1..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Sun, 8 Jun 2014 16:32:59 +0300
-Subject: core-util: Add pa_get_config_home_dir()
-
-Change-Id: I6aa3df386a7414563b03435683bad2596cf60b8b
----
- src/pulsecore/core-util.c | 58 ++++++++++++++++++++++++++++++++---------------
- src/pulsecore/core-util.h |  1 +
- 2 files changed, 41 insertions(+), 18 deletions(-)
-
-diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
-index 99aa51f..2569cfd 100644
---- a/src/pulsecore/core-util.c
-+++ b/src/pulsecore/core-util.c
-@@ -1581,16 +1581,6 @@ int pa_unlock_lockfile(const char *fn, int fd) {
-     return r;
- }
--static char *get_config_home(char *home) {
--    char *t;
--
--    t = getenv("XDG_CONFIG_HOME");
--    if (t)
--        return pa_xstrdup(t);
--
--    return pa_sprintf_malloc("%s" PA_PATH_SEP ".config", home);
--}
--
- static int check_ours(const char *p) {
-     struct stat st;
-@@ -1608,7 +1598,7 @@ static int check_ours(const char *p) {
- }
- static char *get_pulse_home(void) {
--    char *h, *ret, *config_home;
-+    char *h, *ret;
-     int t;
-     h = pa_get_home_dir_malloc();
-@@ -1626,17 +1616,14 @@ static char *get_pulse_home(void) {
-     /* If the old directory exists, use it. */
-     ret = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
--    if (access(ret, F_OK) >= 0) {
--        free(h);
-+    pa_xfree(h);
-+    if (access(ret, F_OK) >= 0)
-         return ret;
--    }
-     free(ret);
-     /* Otherwise go for the XDG compliant directory. */
--    config_home = get_config_home(h);
--    free(h);
--    ret = pa_sprintf_malloc("%s" PA_PATH_SEP "pulse", config_home);
--    free(config_home);
-+    if (pa_get_config_home_dir(false, &ret) < 0)
-+        return NULL;
-     return ret;
- }
-@@ -1702,6 +1689,41 @@ int pa_append_to_home_dir(const char *path, char **_r) {
-     return 0;
- }
-+int pa_get_config_home_dir(bool use_machine_id, char **_r) {
-+    const char *e;
-+    char *base = NULL;
-+    int r = 0;
-+    char *machine_id = NULL;
-+
-+    pa_assert(_r);
-+
-+    e = getenv("XDG_CONFIG_HOME");
-+    if (e && *e)
-+        base = pa_sprintf_malloc("%s" PA_PATH_SEP "pulse", e);
-+    else {
-+        r = pa_append_to_home_dir(".config" PA_PATH_SEP "pulse", &base);
-+        if (r < 0)
-+            goto finish;
-+    }
-+
-+    if (use_machine_id) {
-+        machine_id = pa_machine_id();
-+        if (!machine_id) {
-+            r = -PA_ERR_NOENTITY;
-+            goto finish;
-+        }
-+
-+        *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", base, machine_id);
-+    } else
-+        *_r = pa_xstrdup(base);
-+
-+finish:
-+    pa_xfree(machine_id);
-+    pa_xfree(base);
-+
-+    return r;
-+}
-+
- char *pa_get_binary_name_malloc(void) {
-     char *t;
-     size_t allocated = 128;
-diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
-index 05d628e..e222874 100644
---- a/src/pulsecore/core-util.h
-+++ b/src/pulsecore/core-util.h
-@@ -138,6 +138,7 @@ char *pa_get_runtime_dir(void);
- char *pa_get_state_dir(void);
- char *pa_get_home_dir_malloc(void);
- int pa_append_to_home_dir(const char *path, char **_r);
-+int pa_get_config_home_dir(bool use_machine_id, char **_r);
- char *pa_get_binary_name_malloc(void);
- char *pa_runtime_path(const char *fn);
- char *pa_state_path(const char *fn, bool prepend_machine_id);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0093-core-util-Add-pa_append_to_config_home_dir.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0093-core-util-Add-pa_append_to_config_home_dir.patch
deleted file mode 100644 (file)
index da7a6ef..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Sun, 8 Jun 2014 16:33:00 +0300
-Subject: core-util: Add pa_append_to_config_home_dir()
-
-Change-Id: Ib4e6a096a740a61188220a983f26ecea434f6200
----
- src/pulsecore/core-util.c | 16 ++++++++++++++++
- src/pulsecore/core-util.h |  1 +
- 2 files changed, 17 insertions(+)
-
-diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
-index 2569cfd..dbe9ec1 100644
---- a/src/pulsecore/core-util.c
-+++ b/src/pulsecore/core-util.c
-@@ -1724,6 +1724,22 @@ finish:
-     return r;
- }
-+int pa_append_to_config_home_dir(const char *path, bool use_machine_id, char **_r) {
-+    int r;
-+    char *config_home_dir;
-+
-+    pa_assert(path);
-+    pa_assert(_r);
-+
-+    r = pa_get_config_home_dir(use_machine_id, &config_home_dir);
-+    if (r < 0)
-+        return r;
-+
-+    *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", config_home_dir, path);
-+    pa_xfree(config_home_dir);
-+    return 0;
-+}
-+
- char *pa_get_binary_name_malloc(void) {
-     char *t;
-     size_t allocated = 128;
-diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
-index e222874..4968385 100644
---- a/src/pulsecore/core-util.h
-+++ b/src/pulsecore/core-util.h
-@@ -139,6 +139,7 @@ char *pa_get_state_dir(void);
- char *pa_get_home_dir_malloc(void);
- int pa_append_to_home_dir(const char *path, char **_r);
- int pa_get_config_home_dir(bool use_machine_id, char **_r);
-+int pa_append_to_config_home_dir(const char *path, bool use_machine_id, char **_r);
- char *pa_get_binary_name_malloc(void);
- char *pa_runtime_path(const char *fn);
- char *pa_state_path(const char *fn, bool prepend_machine_id);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0094-core-Create-the-config-home-directory-on-startup.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0094-core-Create-the-config-home-directory-on-startup.patch
deleted file mode 100644 (file)
index 2d86fde..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Tue, 17 Jun 2014 19:35:21 +0300
-Subject: core: Create the config home directory on startup
-
-This avoids the need to check for the existence of the config home
-directory every time some file needs to be opened from that directory.
-
-Change-Id: I449c61aa46eaea3f8c7eb0aa040310db58421828
----
- src/pulsecore/core.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
-diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
-index e6f2dfc..4a66f80 100644
---- a/src/pulsecore/core.c
-+++ b/src/pulsecore/core.c
-@@ -24,6 +24,7 @@
- #include <config.h>
- #endif
-+#include <errno.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <signal.h>
-@@ -33,6 +34,7 @@
- #include <pulse/xmalloc.h>
- #include <pulsecore/module.h>
-+#include <pulsecore/core-error.h>
- #include <pulsecore/core-rtclock.h>
- #include <pulsecore/core-util.h>
- #include <pulsecore/core-scache.h>
-@@ -64,12 +66,22 @@ static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t o
- static void core_free(pa_object *o);
- pa_core* pa_core_new(pa_mainloop_api *m, bool shared, size_t shm_size) {
-+    int r;
-+    char *config_home_dir;
-     pa_core* c;
-     pa_mempool *pool;
-     int j;
-     pa_assert(m);
-+    r = pa_get_config_home_dir(true, &config_home_dir);
-+    if (r >= 0) {
-+        r = pa_make_secure_dir(config_home_dir, 0700, (uid_t) -1, (gid_t) -1, true);
-+        pa_xfree(config_home_dir);
-+        if (r < 0)
-+            pa_log("Failed to create config home directory (%s): %s", config_home_dir, pa_cstrerror(errno));
-+    }
-+
-     if (shared) {
-         if (!(pool = pa_mempool_new(shared, shm_size))) {
-             pa_log_warn("failed to allocate shared memory pool. Falling back to a normal memory pool.");
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0095-alsa-Handle-unlinking-of-uninitialized-streams-grace.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0095-alsa-Handle-unlinking-of-uninitialized-streams-grace.patch
deleted file mode 100644 (file)
index 54b6530..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 4 Aug 2014 15:33:01 +0300
-Subject: alsa: Handle unlinking of uninitialized streams gracefully
-
-There should be no assumptions about what has been initialized when
-the unlink hook is fired.
-
-Change-Id: I7502f0e7a3d244413dd806bc8657014999c9b9b3
----
- src/modules/alsa/module-alsa-card.c | 12 ++++++++++--
- 1 file changed, 10 insertions(+), 2 deletions(-)
-
-diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
-index 1e63230..7c408ee 100644
---- a/src/modules/alsa/module-alsa-card.c
-+++ b/src/modules/alsa/module-alsa-card.c
-@@ -579,7 +579,11 @@ static pa_hook_result_t sink_input_unlink_hook_callback(pa_core *c, pa_sink_inpu
-     const char *role;
-     pa_sink *sink = sink_input->sink;
--    pa_assert(sink);
-+    if (!sink)
-+        return PA_HOOK_OK;
-+
-+    if (!sink_input->proplist)
-+        return PA_HOOK_OK;
-     role = pa_proplist_gets(sink_input->proplist, PA_PROP_MEDIA_ROLE);
-@@ -594,7 +598,11 @@ static pa_hook_result_t source_output_unlink_hook_callback(pa_core *c, pa_source
-     const char *role;
-     pa_source *source = source_output->source;
--    pa_assert(source);
-+    if (!source)
-+        return PA_HOOK_OK;
-+
-+    if (!source_output->proplist)
-+        return PA_HOOK_OK;
-     role = pa_proplist_gets(source_output->proplist, PA_PROP_MEDIA_ROLE);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0096-role-cork-Handle-unlinking-of-uninitialized-streams-.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0096-role-cork-Handle-unlinking-of-uninitialized-streams-.patch
deleted file mode 100644 (file)
index 0bd8821..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 4 Aug 2014 15:59:06 +0300
-Subject: role-cork: Handle unlinking of uninitialized streams gracefully
-
-There should be no assumptions about what has been initialized when
-the unlink hook is fired.
-
-Change-Id: I4ea4372570e7a0a83c31caab6e2e6781a98cd3ad
----
- src/modules/module-role-cork.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/modules/module-role-cork.c b/src/modules/module-role-cork.c
-index 8ca2109..d72350c 100644
---- a/src/modules/module-role-cork.c
-+++ b/src/modules/module-role-cork.c
-@@ -162,6 +162,9 @@ static pa_hook_result_t process(struct userdata *u, pa_sink_input *i, bool creat
-     if (!create)
-         pa_hashmap_remove(u->cork_state, i);
-+    if (!i->proplist)
-+        return PA_HOOK_OK;
-+
-     if (!(role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE)))
-         return PA_HOOK_OK;
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0097-role-ducking-Handle-unlinking-of-uninitialized-strea.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0097-role-ducking-Handle-unlinking-of-uninitialized-strea.patch
deleted file mode 100644 (file)
index 0f3d20a..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 4 Aug 2014 16:00:01 +0300
-Subject: role-ducking: Handle unlinking of uninitialized streams gracefully
-
-There should be no assumptions about what has been initialized when
-the unlink hook is fired.
-
-Change-Id: Id3c069093894bf508fbc0be75db046ff875ce965
----
- src/modules/module-role-ducking.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/modules/module-role-ducking.c b/src/modules/module-role-ducking.c
-index 9947871..d1ae357 100644
---- a/src/modules/module-role-ducking.c
-+++ b/src/modules/module-role-ducking.c
-@@ -159,6 +159,9 @@ static pa_hook_result_t process(struct userdata *u, pa_sink_input *i, bool duck)
-     pa_assert(u);
-     pa_sink_input_assert_ref(i);
-+    if (!i->proplist)
-+        return PA_HOOK_OK;
-+
-     if (!(role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE)))
-         return PA_HOOK_OK;
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0098-core-util-Add-pa_boolean_to_string.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0098-core-util-Add-pa_boolean_to_string.patch
deleted file mode 100644 (file)
index ad48a21..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 4 Aug 2014 20:31:00 +0300
-Subject: core-util: Add pa_boolean_to_string()
-
-I need to save booleans in a plain text database, and the existing
-pa_yes_no() is not good, because it will do translation in the next
-PulseAudio release.
-
-Change-Id: I85f12da01aa0eb3d5c555350bd14ba337fbcc25b
----
- src/pulsecore/core-util.h | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
-index 4968385..c108968 100644
---- a/src/pulsecore/core-util.h
-+++ b/src/pulsecore/core-util.h
-@@ -89,6 +89,10 @@ int pa_parse_boolean(const char *s) PA_GCC_PURE;
- int pa_parse_volume(const char *s, pa_volume_t *volume);
-+static inline const char *pa_boolean_to_string(bool b) {
-+    return b ? "true" : "false";
-+}
-+
- static inline const char *pa_yes_no(bool b) {
-     return b ? "yes" : "no";
- }
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0099-sink-input-source-output-Assign-to-reference_ratio-f.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0099-sink-input-source-output-Assign-to-reference_ratio-f.patch
deleted file mode 100644 (file)
index d8c815a..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 4 Aug 2014 20:57:55 +0300
-Subject: sink-input,
- source-output: Assign to reference_ratio from a single place
-
-This makes it easy to log a message every time the reference ratio
-changes. I also need to add a hook for reference ratio changes, but
-that need will go away if the stream relative volume controls will be
-created by the core in the future.
-
-Change-Id: I2344ba7825f76cd72241599bd138b21e16555e01
----
- src/pulsecore/sink-input.c    | 28 ++++++++++++++++++++++++++--
- src/pulsecore/sink-input.h    |  6 ++++++
- src/pulsecore/sink.c          | 11 +++++++----
- src/pulsecore/source-output.c | 26 +++++++++++++++++++++++++-
- src/pulsecore/source-output.h |  6 ++++++
- src/pulsecore/source.c        | 11 +++++++----
- 6 files changed, 77 insertions(+), 11 deletions(-)
-
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index 9d13269..57c906d 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -1305,7 +1305,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, bool s
-         /* OK, we are in normal volume mode. The volume only affects
-          * ourselves */
-         set_real_ratio(i, volume);
--        i->reference_ratio = i->volume;
-+        pa_sink_input_set_reference_ratio(i, &i->volume);
-         /* Copy the new soft_volume to the thread_info struct */
-         pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
-@@ -1757,7 +1757,7 @@ static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
-             pa_cvolume_reset(&new_volume, i->volume.channels);
-             pa_sink_input_set_volume_direct(i, &new_volume);
--            pa_cvolume_reset(&i->reference_ratio, i->reference_ratio.channels);
-+            pa_sink_input_set_reference_ratio(i, &new_volume);
-             pa_assert(pa_cvolume_is_norm(&i->real_ratio));
-             pa_assert(pa_cvolume_equal(&i->soft_volume, &i->volume_factor));
-         }
-@@ -2329,3 +2329,27 @@ void pa_sink_input_set_volume_direct(pa_sink_input *i, const pa_cvolume *volume)
-     pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
-     pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED], i);
- }
-+
-+/* Called from the main thread. */
-+void pa_sink_input_set_reference_ratio(pa_sink_input *i, const pa_cvolume *ratio) {
-+    pa_cvolume old_ratio;
-+    char old_ratio_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+    char new_ratio_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+
-+    pa_assert(i);
-+    pa_assert(ratio);
-+
-+    old_ratio = i->reference_ratio;
-+
-+    if (pa_cvolume_equal(ratio, &old_ratio))
-+        return;
-+
-+    i->reference_ratio = *ratio;
-+
-+    if (!PA_SINK_INPUT_IS_LINKED(i->state))
-+        return;
-+
-+    pa_log_debug("Sink input %u reference ratio changed from %s to %s.", i->index,
-+                 pa_cvolume_snprint_verbose(old_ratio_str, sizeof(old_ratio_str), &old_ratio, &i->channel_map, true),
-+                 pa_cvolume_snprint_verbose(new_ratio_str, sizeof(new_ratio_str), ratio, &i->channel_map, true));
-+}
-diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
-index 1bd3eee..e5b0ae8 100644
---- a/src/pulsecore/sink-input.h
-+++ b/src/pulsecore/sink-input.h
-@@ -437,6 +437,12 @@ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret);
-  * and fires change notifications. */
- void pa_sink_input_set_volume_direct(pa_sink_input *i, const pa_cvolume *volume);
-+/* Called from the main thread, from sink.c only. This shouldn't be a public
-+ * function, but the flat volume logic in sink.c currently needs a way to
-+ * directly set the sink input reference ratio. This function simply sets
-+ * i->reference_ratio and logs a message if the value changes. */
-+void pa_sink_input_set_reference_ratio(pa_sink_input *i, const pa_cvolume *ratio);
-+
- #define pa_sink_input_assert_io_context(s) \
-     pa_assert(pa_thread_mq_get() || !PA_SINK_INPUT_IS_LINKED((s)->state))
-diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
-index 41cffcc..400d06d 100644
---- a/src/pulsecore/sink.c
-+++ b/src/pulsecore/sink.c
-@@ -1670,6 +1670,7 @@ void pa_sink_leave_passthrough(pa_sink *s) {
- static void compute_reference_ratio(pa_sink_input *i) {
-     unsigned c = 0;
-     pa_cvolume remapped;
-+    pa_cvolume ratio;
-     pa_assert(i);
-     pa_assert(pa_sink_flat_volume_enabled(i->sink));
-@@ -1684,7 +1685,7 @@ static void compute_reference_ratio(pa_sink_input *i) {
-     remapped = i->sink->reference_volume;
-     pa_cvolume_remap(&remapped, &i->sink->channel_map, &i->channel_map);
--    i->reference_ratio.channels = i->sample_spec.channels;
-+    ratio = i->reference_ratio;
-     for (c = 0; c < i->sample_spec.channels; c++) {
-@@ -1694,14 +1695,16 @@ static void compute_reference_ratio(pa_sink_input *i) {
-         /* Don't update the reference ratio unless necessary */
-         if (pa_sw_volume_multiply(
--                    i->reference_ratio.values[c],
-+                    ratio.values[c],
-                     remapped.values[c]) == i->volume.values[c])
-             continue;
--        i->reference_ratio.values[c] = pa_sw_volume_divide(
-+        ratio.values[c] = pa_sw_volume_divide(
-                 i->volume.values[c],
-                 remapped.values[c]);
-     }
-+
-+    pa_sink_input_set_reference_ratio(i, &ratio);
- }
- /* Called from main context. Only called for the root sink in volume sharing
-@@ -2195,7 +2198,7 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
-             /* 2. Since the sink's reference and real volumes are equal
-              * now our ratios should be too. */
--            i->reference_ratio = i->real_ratio;
-+            pa_sink_input_set_reference_ratio(i, &i->real_ratio);
-             /* 3. Recalculate the new stream reference volume based on the
-              * reference ratio and the sink's reference volume.
-diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
-index d3d15f1..0012be3 100644
---- a/src/pulsecore/source-output.c
-+++ b/src/pulsecore/source-output.c
-@@ -1313,7 +1313,7 @@ static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) {
-             pa_cvolume_reset(&new_volume, o->volume.channels);
-             pa_source_output_set_volume_direct(o, &new_volume);
--            pa_cvolume_reset(&o->reference_ratio, o->reference_ratio.channels);
-+            pa_source_output_set_reference_ratio(o, &new_volume);
-             pa_assert(pa_cvolume_is_norm(&o->real_ratio));
-             pa_assert(pa_cvolume_equal(&o->soft_volume, &o->volume_factor));
-         }
-@@ -1695,3 +1695,27 @@ void pa_source_output_set_volume_direct(pa_source_output *o, const pa_cvolume *v
-     pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
-     pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED], o);
- }
-+
-+/* Called from the main thread. */
-+void pa_source_output_set_reference_ratio(pa_source_output *o, const pa_cvolume *ratio) {
-+    pa_cvolume old_ratio;
-+    char old_ratio_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+    char new_ratio_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
-+
-+    pa_assert(o);
-+    pa_assert(ratio);
-+
-+    old_ratio = o->reference_ratio;
-+
-+    if (pa_cvolume_equal(ratio, &old_ratio))
-+        return;
-+
-+    o->reference_ratio = *ratio;
-+
-+    if (!PA_SOURCE_OUTPUT_IS_LINKED(o->state))
-+        return;
-+
-+    pa_log_debug("Source output %u reference ratio changed from %s to %s.", o->index,
-+                 pa_cvolume_snprint_verbose(old_ratio_str, sizeof(old_ratio_str), &old_ratio, &o->channel_map, true),
-+                 pa_cvolume_snprint_verbose(new_ratio_str, sizeof(new_ratio_str), ratio, &o->channel_map, true));
-+}
-diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
-index 73170d3..3ed950b 100644
---- a/src/pulsecore/source-output.h
-+++ b/src/pulsecore/source-output.h
-@@ -359,6 +359,12 @@ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output
-  * o->volume and fires change notifications. */
- void pa_source_output_set_volume_direct(pa_source_output *o, const pa_cvolume *volume);
-+/* Called from the main thread, from source.c only. This shouldn't be a public
-+ * function, but the flat volume logic in source.c currently needs a way to
-+ * directly set the source output reference ratio. This function simply sets
-+ * o->reference_ratio and logs a message if the value changes. */
-+void pa_source_output_set_reference_ratio(pa_source_output *o, const pa_cvolume *ratio);
-+
- #define pa_source_output_assert_io_context(s) \
-     pa_assert(pa_thread_mq_get() || !PA_SOURCE_OUTPUT_IS_LINKED((s)->state))
-diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
-index db7f667..293ab28 100644
---- a/src/pulsecore/source.c
-+++ b/src/pulsecore/source.c
-@@ -1214,6 +1214,7 @@ void pa_source_leave_passthrough(pa_source *s) {
- static void compute_reference_ratio(pa_source_output *o) {
-     unsigned c = 0;
-     pa_cvolume remapped;
-+    pa_cvolume ratio;
-     pa_assert(o);
-     pa_assert(pa_source_flat_volume_enabled(o->source));
-@@ -1228,7 +1229,7 @@ static void compute_reference_ratio(pa_source_output *o) {
-     remapped = o->source->reference_volume;
-     pa_cvolume_remap(&remapped, &o->source->channel_map, &o->channel_map);
--    o->reference_ratio.channels = o->sample_spec.channels;
-+    ratio = o->reference_ratio;
-     for (c = 0; c < o->sample_spec.channels; c++) {
-@@ -1238,14 +1239,16 @@ static void compute_reference_ratio(pa_source_output *o) {
-         /* Don't update the reference ratio unless necessary */
-         if (pa_sw_volume_multiply(
--                    o->reference_ratio.values[c],
-+                    ratio.values[c],
-                     remapped.values[c]) == o->volume.values[c])
-             continue;
--        o->reference_ratio.values[c] = pa_sw_volume_divide(
-+        ratio.values[c] = pa_sw_volume_divide(
-                 o->volume.values[c],
-                 remapped.values[c]);
-     }
-+
-+    pa_source_output_set_reference_ratio(o, &ratio);
- }
- /* Called from main context. Only called for the root source in volume sharing
-@@ -1712,7 +1715,7 @@ static void propagate_real_volume(pa_source *s, const pa_cvolume *old_real_volum
-             /* 2. Since the source's reference and real volumes are equal
-              * now our ratios should be too. */
--            o->reference_ratio = o->real_ratio;
-+            pa_source_output_set_reference_ratio(o, &o->real_ratio);
-             /* 3. Recalculate the new stream reference volume based on the
-              * reference ratio and the sink's reference volume.
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0100-sink-input-source-output-Add-hooks-for-reference-rat.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0100-sink-input-source-output-Add-hooks-for-reference-rat.patch
deleted file mode 100644 (file)
index cfbfdde..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 4 Aug 2014 21:26:17 +0300
-Subject: sink-input, source-output: Add hooks for reference ratio changes
-
-Needed for implementing relative volume controls for streams in
-module-volume-api. The plan is to create those controls in the core,
-though, and these hooks won't be needed at that point any more.
-
-Change-Id: Id30f38f4adfa9ede7bd0b12b484fe329ca1a3991
----
- src/pulsecore/core.h          | 2 ++
- src/pulsecore/sink-input.c    | 2 ++
- src/pulsecore/sink-input.h    | 3 ++-
- src/pulsecore/source-output.c | 2 ++
- src/pulsecore/source-output.h | 3 ++-
- 5 files changed, 10 insertions(+), 2 deletions(-)
-
-diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
-index 1f042b9..0e8f709 100644
---- a/src/pulsecore/core.h
-+++ b/src/pulsecore/core.h
-@@ -100,6 +100,7 @@ typedef enum pa_core_hook {
-     PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED,
-     PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED,
-     PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED,
-+    PA_CORE_HOOK_SINK_INPUT_REFERENCE_RATIO_CHANGED,
-     PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED,
-     PA_CORE_HOOK_SINK_INPUT_SEND_EVENT,
-     PA_CORE_HOOK_SOURCE_OUTPUT_NEW,
-@@ -113,6 +114,7 @@ typedef enum pa_core_hook {
-     PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED,
-     PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED,
-     PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED,
-+    PA_CORE_HOOK_SOURCE_OUTPUT_REFERENCE_RATIO_CHANGED,
-     PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED,
-     PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT,
-     PA_CORE_HOOK_CLIENT_NEW,
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index 57c906d..d62be6f 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -2352,4 +2352,6 @@ void pa_sink_input_set_reference_ratio(pa_sink_input *i, const pa_cvolume *ratio
-     pa_log_debug("Sink input %u reference ratio changed from %s to %s.", i->index,
-                  pa_cvolume_snprint_verbose(old_ratio_str, sizeof(old_ratio_str), &old_ratio, &i->channel_map, true),
-                  pa_cvolume_snprint_verbose(new_ratio_str, sizeof(new_ratio_str), ratio, &i->channel_map, true));
-+
-+    pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_REFERENCE_RATIO_CHANGED], i);
- }
-diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
-index e5b0ae8..c99ce1f 100644
---- a/src/pulsecore/sink-input.h
-+++ b/src/pulsecore/sink-input.h
-@@ -440,7 +440,8 @@ void pa_sink_input_set_volume_direct(pa_sink_input *i, const pa_cvolume *volume)
- /* Called from the main thread, from sink.c only. This shouldn't be a public
-  * function, but the flat volume logic in sink.c currently needs a way to
-  * directly set the sink input reference ratio. This function simply sets
-- * i->reference_ratio and logs a message if the value changes. */
-+ * i->reference_ratio and logs a message and fires a hook if the value
-+ * changes. */
- void pa_sink_input_set_reference_ratio(pa_sink_input *i, const pa_cvolume *ratio);
- #define pa_sink_input_assert_io_context(s) \
-diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
-index 0012be3..ae5a92c 100644
---- a/src/pulsecore/source-output.c
-+++ b/src/pulsecore/source-output.c
-@@ -1718,4 +1718,6 @@ void pa_source_output_set_reference_ratio(pa_source_output *o, const pa_cvolume
-     pa_log_debug("Source output %u reference ratio changed from %s to %s.", o->index,
-                  pa_cvolume_snprint_verbose(old_ratio_str, sizeof(old_ratio_str), &old_ratio, &o->channel_map, true),
-                  pa_cvolume_snprint_verbose(new_ratio_str, sizeof(new_ratio_str), ratio, &o->channel_map, true));
-+
-+    pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_REFERENCE_RATIO_CHANGED], o);
- }
-diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
-index 3ed950b..60bbda8 100644
---- a/src/pulsecore/source-output.h
-+++ b/src/pulsecore/source-output.h
-@@ -362,7 +362,8 @@ void pa_source_output_set_volume_direct(pa_source_output *o, const pa_cvolume *v
- /* Called from the main thread, from source.c only. This shouldn't be a public
-  * function, but the flat volume logic in source.c currently needs a way to
-  * directly set the source output reference ratio. This function simply sets
-- * o->reference_ratio and logs a message if the value changes. */
-+ * o->reference_ratio and logs a message and fires a hook if the value
-+ * changes. */
- void pa_source_output_set_reference_ratio(pa_source_output *o, const pa_cvolume *ratio);
- #define pa_source_output_assert_io_context(s) \
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0101-sink-input-source-output-Use-new_data.volume-only-fo.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0101-sink-input-source-output-Use-new_data.volume-only-fo.patch
deleted file mode 100644 (file)
index 13d5221..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Mon, 4 Aug 2014 21:42:45 +0300
-Subject: sink-input,
- source-output: Use new_data.volume only for absolute volume
-
-This simplifies life for modules that care about the initial volume of
-streams. new_data.volume will always be the absolute volume (assuming
-that flat volume is in effect) and new_data.reference_ratio will
-always be the relative volume.
-
-This will be especially useful when creating volume controls (absolute
-and relative) for new streams in module-volume-api.
-
-Change-Id: Ibca033c8441dde35a0b43d9276c41e383c675306
----
- src/modules/module-match.c          |  2 +-
- src/modules/module-stream-restore.c |  8 ++---
- src/pulsecore/play-memblockq.c      |  2 +-
- src/pulsecore/protocol-native.c     |  6 ++--
- src/pulsecore/sink-input.c          | 71 +++++++++++++++++++++++++------------
- src/pulsecore/sink-input.h          |  5 +--
- src/pulsecore/sound-file-stream.c   |  2 +-
- src/pulsecore/source-output.c       | 71 +++++++++++++++++++++++++------------
- src/pulsecore/source-output.h       |  5 +--
- 9 files changed, 111 insertions(+), 61 deletions(-)
-
-diff --git a/src/modules/module-match.c b/src/modules/module-match.c
-index 8ce3f00..7d73086 100644
---- a/src/modules/module-match.c
-+++ b/src/modules/module-match.c
-@@ -234,7 +234,7 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
-                 pa_cvolume cv;
-                 pa_log_debug("changing volume of sink input '%s' to 0x%03x", n, r->volume);
-                 pa_cvolume_set(&cv, si->sample_spec.channels, r->volume);
--                pa_sink_input_new_data_set_volume(si, &cv);
-+                pa_sink_input_new_data_set_volume(si, &cv, true);
-             } else
-                 pa_log_debug("the volume of sink input '%s' is not writable, can't change it", n);
-         }
-diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
-index 4fc5645..1aa8a07 100644
---- a/src/modules/module-stream-restore.c
-+++ b/src/modules/module-stream-restore.c
-@@ -1482,9 +1482,7 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
-                 v = e->volume;
-                 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
--                pa_sink_input_new_data_set_volume(new_data, &v);
--
--                new_data->volume_is_absolute = false;
-+                pa_sink_input_new_data_set_volume(new_data, &v, true);
-                 new_data->save_volume = true;
-             }
-         }
-@@ -1579,9 +1577,7 @@ static pa_hook_result_t source_output_fixate_hook_callback(pa_core *c, pa_source
-                 v = e->volume;
-                 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
--                pa_source_output_new_data_set_volume(new_data, &v);
--
--                new_data->volume_is_absolute = false;
-+                pa_source_output_new_data_set_volume(new_data, &v, true);
-                 new_data->save_volume = true;
-             }
-         }
-diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c
-index ff0c52b..055fd2a 100644
---- a/src/pulsecore/play-memblockq.c
-+++ b/src/pulsecore/play-memblockq.c
-@@ -203,7 +203,7 @@ pa_sink_input* pa_memblockq_sink_input_new(
-     data.driver = __FILE__;
-     pa_sink_input_new_data_set_sample_spec(&data, ss);
-     pa_sink_input_new_data_set_channel_map(&data, map);
--    pa_sink_input_new_data_set_volume(&data, volume);
-+    pa_sink_input_new_data_set_volume(&data, volume, false);
-     pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
-     data.flags |= flags;
-diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
-index 21e02fe..b209737 100644
---- a/src/pulsecore/protocol-native.c
-+++ b/src/pulsecore/protocol-native.c
-@@ -679,8 +679,7 @@ static record_stream* record_stream_new(
-         pa_source_output_new_data_set_formats(&data, formats);
-     data.direct_on_input = direct_on_input;
-     if (volume) {
--        pa_source_output_new_data_set_volume(&data, volume);
--        data.volume_is_absolute = !relative_volume;
-+        pa_source_output_new_data_set_volume(&data, volume, relative_volume);
-         data.save_volume = false;
-     }
-     if (muted_set) {
-@@ -1149,8 +1148,7 @@ static playback_stream* playback_stream_new(
-         formats = NULL;
-     }
-     if (volume) {
--        pa_sink_input_new_data_set_volume(&data, volume);
--        data.volume_is_absolute = !relative_volume;
-+        pa_sink_input_new_data_set_volume(&data, volume, relative_volume);
-         data.save_volume = false;
-     }
-     if (muted_set) {
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index d62be6f..796a567 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -145,12 +145,44 @@ bool pa_sink_input_new_data_is_passthrough(pa_sink_input_new_data *data) {
-     return false;
- }
--void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
-+void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume, bool relative) {
-+    pa_cvolume remapped_sink_volume;
-+
-     pa_assert(data);
-     pa_assert(data->volume_writable);
-     if ((data->volume_is_set = !!volume))
-         data->volume = *volume;
-+    else
-+        return;
-+
-+    data->volume_is_relative = relative;
-+
-+    if (data->sink) {
-+        remapped_sink_volume = data->sink->reference_volume;
-+        pa_cvolume_remap(&remapped_sink_volume, &data->sink->channel_map, &data->channel_map);
-+    }
-+
-+    if (relative) {
-+        data->reference_ratio = data->volume;
-+
-+        if (data->sink && pa_sink_flat_volume_enabled(data->sink)) {
-+            /* Let's keep data->volume as absolute, so that modules won't ever
-+             * have to specially handle the relative case. Modules inspecting
-+             * the volume should do so in the FIXATE hook, and at that point
-+             * data->sink is always set. data->volume is relative only during
-+             * the time before routing, and only if the sink input owner
-+             * requested relative volume. */
-+            pa_sw_cvolume_multiply(&data->volume, &data->volume, &remapped_sink_volume);
-+            data->volume_is_relative = false;
-+        }
-+    } else {
-+        if (data->sink)
-+            pa_sw_cvolume_divide(&data->reference_ratio, &data->volume, &remapped_sink_volume);
-+
-+        /* If data->sink is not set, we can't compute the reference ratio.
-+         * We'll compute it after routing. */
-+    }
- }
- void pa_sink_input_new_data_add_volume_factor(pa_sink_input_new_data *data, const char *key, const pa_cvolume *volume_factor) {
-@@ -292,6 +324,7 @@ int pa_sink_input_new(
-     int r;
-     char *pt;
-     char *memblockq_name;
-+    pa_cvolume v;
-     pa_assert(_i);
-     pa_assert(core);
-@@ -380,18 +413,17 @@ int pa_sink_input_new(
-     if (r != PA_OK)
-         return r;
-+    /* Now that the routing is done, we can finalize the volume if it has been
-+     * set. If the set volume is relative, we convert it to absolute, and if
-+     * it's absolute, we compute the reference ratio. */
-+    if (data->volume_is_set)
-+        pa_sink_input_new_data_set_volume(data, &data->volume, data->volume_is_relative);
-+
-     /* Don't restore (or save) stream volume for passthrough streams and
-      * prevent attenuation/gain */
-     if (pa_sink_input_new_data_is_passthrough(data)) {
--        data->volume_is_set = true;
--        pa_cvolume_reset(&data->volume, data->sample_spec.channels);
--        data->volume_is_absolute = true;
--        data->save_volume = false;
--    }
--
--    if (!data->volume_is_set) {
--        pa_cvolume_reset(&data->volume, data->sample_spec.channels);
--        data->volume_is_absolute = false;
-+        pa_cvolume_reset(&v, data->sample_spec.channels);
-+        pa_sink_input_new_data_set_volume(data, &v, false);
-         data->save_volume = false;
-     }
-@@ -432,6 +464,12 @@ int pa_sink_input_new(
-     if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0)
-         return r;
-+    if (!data->volume_is_set) {
-+        pa_cvolume_reset(&v, data->sample_spec.channels);
-+        pa_sink_input_new_data_set_volume(data, &v, true);
-+        data->save_volume = false;
-+    }
-+
-     if ((data->flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND) &&
-         pa_sink_get_state(data->sink) == PA_SINK_SUSPENDED) {
-         pa_log_warn("Failed to create sink input: sink is suspended.");
-@@ -482,18 +520,7 @@ int pa_sink_input_new(
-     i->sample_spec = data->sample_spec;
-     i->channel_map = data->channel_map;
-     i->format = pa_format_info_copy(data->format);
--
--    if (!data->volume_is_absolute && pa_sink_flat_volume_enabled(i->sink)) {
--        pa_cvolume remapped;
--
--        /* When the 'absolute' bool is not set then we'll treat the volume
--         * as relative to the sink volume even in flat volume mode */
--        remapped = data->sink->reference_volume;
--        pa_cvolume_remap(&remapped, &data->sink->channel_map, &data->channel_map);
--        pa_sw_cvolume_multiply(&i->volume, &data->volume, &remapped);
--    } else
--        i->volume = data->volume;
--
-+    i->volume = data->volume;
-     i->volume_factor_items = data->volume_factor_items;
-     data->volume_factor_items = NULL;
-     volume_factor_from_hashmap(&i->volume_factor, i->volume_factor_items, i->sample_spec.channels);
-diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
-index c99ce1f..b2d4967 100644
---- a/src/pulsecore/sink-input.h
-+++ b/src/pulsecore/sink-input.h
-@@ -311,6 +311,7 @@ typedef struct pa_sink_input_new_data {
-     pa_idxset *nego_formats;
-     pa_cvolume volume;
-+    pa_cvolume reference_ratio;
-     bool muted:1;
-     pa_hashmap *volume_factor_items, *volume_factor_sink_items;
-@@ -320,7 +321,7 @@ typedef struct pa_sink_input_new_data {
-     bool volume_is_set:1;
-     bool muted_is_set:1;
--    bool volume_is_absolute:1;
-+    bool volume_is_relative:1;
-     bool volume_writable:1;
-@@ -331,7 +332,7 @@ pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data
- void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec);
- void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map);
- bool pa_sink_input_new_data_is_passthrough(pa_sink_input_new_data *data);
--void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume);
-+void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume, bool relative);
- void pa_sink_input_new_data_add_volume_factor(pa_sink_input_new_data *data, const char *key, const pa_cvolume *volume_factor);
- void pa_sink_input_new_data_add_volume_factor_sink(pa_sink_input_new_data *data, const char *key, const pa_cvolume *volume_factor);
- void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, bool mute);
-diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c
-index 33f7337..6886025 100644
---- a/src/pulsecore/sound-file-stream.c
-+++ b/src/pulsecore/sound-file-stream.c
-@@ -302,7 +302,7 @@ int pa_play_file(
-     data.driver = __FILE__;
-     pa_sink_input_new_data_set_sample_spec(&data, &ss);
-     pa_sink_input_new_data_set_channel_map(&data, &cm);
--    pa_sink_input_new_data_set_volume(&data, volume);
-+    pa_sink_input_new_data_set_volume(&data, volume, false);
-     pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, pa_path_get_filename(fname));
-     pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname);
-     pa_sndfile_init_proplist(u->sndfile, data.proplist);
-diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
-index ae5a92c..c929999 100644
---- a/src/pulsecore/source-output.c
-+++ b/src/pulsecore/source-output.c
-@@ -86,12 +86,44 @@ bool pa_source_output_new_data_is_passthrough(pa_source_output_new_data *data) {
-     return false;
- }
--void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const pa_cvolume *volume) {
-+void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const pa_cvolume *volume, bool relative) {
-+    pa_cvolume remapped_source_volume;
-+
-     pa_assert(data);
-     pa_assert(data->volume_writable);
-     if ((data->volume_is_set = !!volume))
-         data->volume = *volume;
-+    else
-+        return;
-+
-+    data->volume_is_relative = relative;
-+
-+    if (data->source) {
-+        remapped_source_volume = data->source->reference_volume;
-+        pa_cvolume_remap(&remapped_source_volume, &data->source->channel_map, &data->channel_map);
-+    }
-+
-+    if (relative) {
-+        data->reference_ratio = data->volume;
-+
-+        if (data->source && pa_source_flat_volume_enabled(data->source)) {
-+            /* Let's keep data->volume as absolute, so that modules won't ever
-+             * have to specially handle the relative case. Modules inspecting
-+             * the volume should do so in the FIXATE hook, and at that point
-+             * data->source is always set. data->volume is relative only during
-+             * the time before routing, and only if the source output owner
-+             * requested relative volume. */
-+            pa_sw_cvolume_multiply(&data->volume, &data->volume, &remapped_source_volume);
-+            data->volume_is_relative = false;
-+        }
-+    } else {
-+        if (data->source)
-+            pa_sw_cvolume_divide(&data->reference_ratio, &data->volume, &remapped_source_volume);
-+
-+        /* If data->source is not set, we can't compute the reference ratio.
-+         * We'll compute it after routing. */
-+    }
- }
- void pa_source_output_new_data_apply_volume_factor(pa_source_output_new_data *data, const pa_cvolume *volume_factor) {
-@@ -226,6 +258,7 @@ int pa_source_output_new(
-     pa_channel_map volume_map;
-     int r;
-     char *pt;
-+    pa_cvolume v;
-     pa_assert(_o);
-     pa_assert(core);
-@@ -316,18 +349,17 @@ int pa_source_output_new(
-     if (r < 0)
-         return r;
-+    /* Now that the routing is done, we can finalize the volume if it has been
-+     * set. If the set volume is relative, we convert it to absolute, and if
-+     * it's absolute, we compute the reference ratio. */
-+    if (data->volume_is_set)
-+        pa_source_output_new_data_set_volume(data, &data->volume, data->volume_is_relative);
-+
-     /* Don't restore (or save) stream volume for passthrough streams and
-      * prevent attenuation/gain */
-     if (pa_source_output_new_data_is_passthrough(data)) {
--        data->volume_is_set = true;
--        pa_cvolume_reset(&data->volume, data->sample_spec.channels);
--        data->volume_is_absolute = true;
--        data->save_volume = false;
--    }
--
--    if (!data->volume_is_set) {
--        pa_cvolume_reset(&data->volume, data->sample_spec.channels);
--        data->volume_is_absolute = false;
-+        pa_cvolume_reset(&v, data->sample_spec.channels);
-+        pa_source_output_new_data_set_volume(data, &v, false);
-         data->save_volume = false;
-     }
-@@ -378,6 +410,12 @@ int pa_source_output_new(
-     if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data)) < 0)
-         return r;
-+    if (!data->volume_is_set) {
-+        pa_cvolume_reset(&v, data->sample_spec.channels);
-+        pa_source_output_new_data_set_volume(data, &v, true);
-+        data->save_volume = false;
-+    }
-+
-     if ((data->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND) &&
-         pa_source_get_state(data->source) == PA_SOURCE_SUSPENDED) {
-         pa_log("Failed to create source output: source is suspended.");
-@@ -427,18 +465,7 @@ int pa_source_output_new(
-     o->sample_spec = data->sample_spec;
-     o->channel_map = data->channel_map;
-     o->format = pa_format_info_copy(data->format);
--
--    if (!data->volume_is_absolute && pa_source_flat_volume_enabled(o->source)) {
--        pa_cvolume remapped;
--
--        /* When the 'absolute' bool is not set then we'll treat the volume
--         * as relative to the source volume even in flat volume mode */
--        remapped = data->source->reference_volume;
--        pa_cvolume_remap(&remapped, &data->source->channel_map, &data->channel_map);
--        pa_sw_cvolume_multiply(&o->volume, &data->volume, &remapped);
--    } else
--        o->volume = data->volume;
--
-+    o->volume = data->volume;
-     o->volume_factor = data->volume_factor;
-     o->volume_factor_source = data->volume_factor_source;
-     o->real_ratio = o->reference_ratio = data->volume;
-diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
-index 60bbda8..dc82af9 100644
---- a/src/pulsecore/source-output.h
-+++ b/src/pulsecore/source-output.h
-@@ -257,6 +257,7 @@ typedef struct pa_source_output_new_data {
-     pa_idxset *nego_formats;
-     pa_cvolume volume, volume_factor, volume_factor_source;
-+    pa_cvolume reference_ratio;
-     bool muted:1;
-     bool sample_spec_is_set:1;
-@@ -265,7 +266,7 @@ typedef struct pa_source_output_new_data {
-     bool volume_is_set:1, volume_factor_is_set:1, volume_factor_source_is_set:1;
-     bool muted_is_set:1;
--    bool volume_is_absolute:1;
-+    bool volume_is_relative:1;
-     bool volume_writable:1;
-@@ -276,7 +277,7 @@ pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_d
- void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, const pa_sample_spec *spec);
- void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map);
- bool pa_source_output_new_data_is_passthrough(pa_source_output_new_data *data);
--void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const pa_cvolume *volume);
-+void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const pa_cvolume *volume, bool relative);
- void pa_source_output_new_data_apply_volume_factor(pa_source_output_new_data *data, const pa_cvolume *volume_factor);
- void pa_source_output_new_data_apply_volume_factor_source(pa_source_output_new_data *data, const pa_cvolume *volume_factor);
- void pa_source_output_new_data_set_muted(pa_source_output_new_data *data, bool mute);
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0102-sink-input-source-output-Add-the-real-object-pointer.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0102-sink-input-source-output-Add-the-real-object-pointer.patch
deleted file mode 100644 (file)
index 35b67f5..0000000
+++ /dev/null
@@ -1,543 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Tue, 5 Aug 2014 12:01:54 +0300
-Subject: sink-input, source-output: Add the real object pointer to new_data
-
-module-volume-api needs the pointer already in the FIXATE hook, where
-it creates the volume control objects. The pointer is needed, because
-otherwise there's no way to correlate the created controls with the
-sink inputs and source outputs.
-
-Since the object is created early, pa_sink_input_new() and
-pa_source_output_new() need to free it in case of failure, so a bunch
-of direct returns were replaced with "goto fails".
-
-Since the object may now be unlinked in a completely uninitialized
-state, I reviewed the unlinking code, and made sure that unlinking is
-performed only once (the "unlinked" flag was needed for this).
-
-Change-Id: I89bee3fb51c54d270ccf856750c5b577babc7905
----
- src/pulsecore/sink-input.c    |  96 ++++++++++++++++++++++++++------------
- src/pulsecore/sink-input.h    |   6 +++
- src/pulsecore/source-output.c | 105 ++++++++++++++++++++++++++++++------------
- src/pulsecore/source-output.h |   6 +++
- 4 files changed, 155 insertions(+), 58 deletions(-)
-
-diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
-index 796a567..d419884 100644
---- a/src/pulsecore/sink-input.c
-+++ b/src/pulsecore/sink-input.c
-@@ -331,6 +331,9 @@ int pa_sink_input_new(
-     pa_assert(data);
-     pa_assert_ctl_context();
-+    i = data->sink_input = pa_msgobject_new(pa_sink_input);
-+    i->state = PA_SINK_INPUT_INIT;
-+
-     if (data->client)
-         pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist);
-@@ -348,22 +351,31 @@ int pa_sink_input_new(
-                                              !(data->flags & PA_SINK_INPUT_FIX_FORMAT),
-                                              !(data->flags & PA_SINK_INPUT_FIX_RATE),
-                                              !(data->flags & PA_SINK_INPUT_FIX_CHANNELS));
--        if (!f)
--            return -PA_ERR_INVALID;
-+        if (!f) {
-+            r = -PA_ERR_INVALID;
-+            goto fail;
-+        }
-         formats = pa_idxset_new(NULL, NULL);
-         pa_idxset_put(formats, f, NULL);
-         pa_sink_input_new_data_set_formats(data, formats);
-     }
--    if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data)) < 0)
--        return r;
-+    pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data);
--    pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID);
-+    if (data->driver && !pa_utf8_valid(data->driver)) {
-+        r = -PA_ERR_INVALID;
-+        goto fail;
-+    }
-     if (!data->sink) {
-         pa_sink *sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK);
--        pa_return_val_if_fail(sink, -PA_ERR_NOENTITY);
-+
-+        if (!sink) {
-+            r = -PA_ERR_NOENTITY;
-+            goto fail;
-+        }
-+
-         pa_sink_input_new_data_set_sink(data, sink, false);
-     }
-@@ -382,13 +394,20 @@ int pa_sink_input_new(
-         PA_IDXSET_FOREACH(format, data->req_formats, idx)
-             pa_log_info(" -- %s", pa_format_info_snprint(fmt, sizeof(fmt), format));
--        return -PA_ERR_NOTSUPPORTED;
-+        r = -PA_ERR_NOTSUPPORTED;
-+        goto fail;
-+    }
-+
-+    if (!PA_SINK_IS_LINKED(pa_sink_get_state(data->sink))) {
-+        r = -PA_ERR_BADSTATE;
-+        goto fail;
-     }
--    pa_return_val_if_fail(PA_SINK_IS_LINKED(pa_sink_get_state(data->sink)), -PA_ERR_BADSTATE);
--    pa_return_val_if_fail(!data->sync_base || (data->sync_base->sink == data->sink
--                                               && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED),
--                          -PA_ERR_INVALID);
-+    if (data->sync_base
-+            && !(data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED)) {
-+        r = -PA_ERR_INVALID;
-+        goto fail;
-+    }
-     /* Routing is done. We have a sink and a format. */
-@@ -399,7 +418,7 @@ int pa_sink_input_new(
-          * modified in pa_format_info_to_sample_spec2(). */
-         r = pa_stream_get_volume_channel_map(&data->volume, data->channel_map_is_set ? &data->channel_map : NULL, data->format, &volume_map);
-         if (r < 0)
--            return r;
-+            goto fail;
-     }
-     /* Now populate the sample spec and channel map according to the final
-@@ -407,11 +426,11 @@ int pa_sink_input_new(
-     r = pa_format_info_to_sample_spec2(data->format, &data->sample_spec, &data->channel_map, &data->sink->sample_spec,
-                                        &data->sink->channel_map);
-     if (r < 0)
--        return r;
-+        goto fail;
-     r = check_passthrough_connection(pa_sink_input_new_data_is_passthrough(data), data->sink);
-     if (r != PA_OK)
--        return r;
-+        goto fail;
-     /* Now that the routing is done, we can finalize the volume if it has been
-      * set. If the set volume is relative, we convert it to absolute, and if
-@@ -453,16 +472,19 @@ int pa_sink_input_new(
-         /* rate update failed, or other parts of sample spec didn't match */
-         pa_log_debug("Could not update sink sample spec to match passthrough stream");
--        return -PA_ERR_NOTSUPPORTED;
-+        r = -PA_ERR_NOTSUPPORTED;
-+        goto fail;
-     }
-     if (data->resample_method == PA_RESAMPLER_INVALID)
-         data->resample_method = core->resample_method;
--    pa_return_val_if_fail(data->resample_method < PA_RESAMPLER_MAX, -PA_ERR_INVALID);
-+    if (data->resample_method >= PA_RESAMPLER_MAX) {
-+        r = -PA_ERR_INVALID;
-+        goto fail;
-+    }
--    if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0)
--        return r;
-+    pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data);
-     if (!data->volume_is_set) {
-         pa_cvolume_reset(&v, data->sample_spec.channels);
-@@ -473,12 +495,14 @@ int pa_sink_input_new(
-     if ((data->flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND) &&
-         pa_sink_get_state(data->sink) == PA_SINK_SUSPENDED) {
-         pa_log_warn("Failed to create sink input: sink is suspended.");
--        return -PA_ERR_BADSTATE;
-+        r = -PA_ERR_BADSTATE;
-+        goto fail;
-     }
-     if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) {
-         pa_log_warn("Failed to create sink input: too many inputs per sink.");
--        return -PA_ERR_TOOLARGE;
-+        r = -PA_ERR_TOOLARGE;
-+        goto fail;
-     }
-     if ((data->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
-@@ -497,16 +521,15 @@ int pa_sink_input_new(
-                           (core->disable_remixing || (data->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
-                           (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) {
-                 pa_log_warn("Unsupported resampling operation.");
--                return -PA_ERR_NOTSUPPORTED;
-+                r = -PA_ERR_NOTSUPPORTED;
-+                goto fail;
-             }
-     }
--    i = pa_msgobject_new(pa_sink_input);
-     i->parent.parent.free = sink_input_free;
-     i->parent.process_msg = pa_sink_input_process_msg;
-     i->core = core;
--    i->state = PA_SINK_INPUT_INIT;
-     i->flags = data->flags;
-     i->proplist = pa_proplist_copy(data->proplist);
-     i->driver = pa_xstrdup(pa_path_get_filename(data->driver));
-@@ -610,6 +633,16 @@ int pa_sink_input_new(
-     *_i = i;
-     return 0;
-+
-+fail:
-+    if (i) {
-+        pa_sink_input_unlink(i);
-+        pa_sink_input_unref(i);
-+    }
-+
-+    data->sink_input = NULL;
-+
-+    return r;
- }
- /* Called from main context */
-@@ -683,6 +716,11 @@ void pa_sink_input_unlink(pa_sink_input *i) {
-     pa_assert(i);
-     pa_assert_ctl_context();
-+    if (i->unlinked)
-+        return;
-+
-+    i->unlinked = true;
-+
-     /* See pa_sink_unlink() for a couple of comments how this function
-      * works */
-@@ -691,7 +729,9 @@ void pa_sink_input_unlink(pa_sink_input *i) {
-     linked = PA_SINK_INPUT_IS_LINKED(i->state);
-     if (linked)
--        pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], i);
-+        pa_idxset_remove_by_data(i->core->sink_inputs, i, NULL);
-+
-+    pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], i);
-     if (i->sync_prev)
-         i->sync_prev->sync_next = i->sync_next;
-@@ -700,8 +740,6 @@ void pa_sink_input_unlink(pa_sink_input *i) {
-     i->sync_prev = i->sync_next = NULL;
--    pa_idxset_remove_by_data(i->core->sink_inputs, i, NULL);
--
-     if (i->sink)
-         if (pa_idxset_remove_by_data(i->sink->inputs, i, NULL))
-             pa_sink_input_unref(i);
-@@ -732,10 +770,10 @@ void pa_sink_input_unlink(pa_sink_input *i) {
-     reset_callbacks(i);
--    if (linked) {
-+    if (linked)
-         pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index);
--        pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], i);
--    }
-+
-+    pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], i);
-     if (i->sink) {
-         if (PA_SINK_IS_LINKED(pa_sink_get_state(i->sink)))
-diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
-index b2d4967..a4c6519 100644
---- a/src/pulsecore/sink-input.h
-+++ b/src/pulsecore/sink-input.h
-@@ -76,6 +76,7 @@ struct pa_sink_input {
-      * pa_sink_input_get_state(). That function will transparently
-      * merge the thread_info.drained value in. */
-     pa_sink_input_state_t state;
-+    bool unlinked;
-     pa_sink_input_flags_t flags;
-     char *driver;                       /* may be NULL */
-@@ -289,6 +290,11 @@ typedef struct pa_sink_input_send_event_hook_data {
- } pa_sink_input_send_event_hook_data;
- typedef struct pa_sink_input_new_data {
-+    /* The sink input object is not properly initialized, so don't access the
-+     * member variables! You can only rely on the state variable being
-+     * initialized to PA_SINK_INPUT_INIT. */
-+    pa_sink_input *sink_input;
-+
-     pa_sink_input_flags_t flags;
-     pa_proplist *proplist;
-diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
-index c929999..60f3391 100644
---- a/src/pulsecore/source-output.c
-+++ b/src/pulsecore/source-output.c
-@@ -265,6 +265,9 @@ int pa_source_output_new(
-     pa_assert(data);
-     pa_assert_ctl_context();
-+    o = data->source_output = pa_msgobject_new(pa_source_output);
-+    o->state = PA_SOURCE_OUTPUT_INIT;
-+
-     if (data->client)
-         pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist);
-@@ -282,28 +285,38 @@ int pa_source_output_new(
-                                              !(data->flags & PA_SOURCE_OUTPUT_FIX_FORMAT),
-                                              !(data->flags & PA_SOURCE_OUTPUT_FIX_RATE),
-                                              !(data->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS));
--        if (!f)
--            return -PA_ERR_INVALID;
-+        if (!f) {
-+            r = -PA_ERR_INVALID;
-+            goto fail;
-+        }
-         formats = pa_idxset_new(NULL, NULL);
-         pa_idxset_put(formats, f, NULL);
-         pa_source_output_new_data_set_formats(data, formats);
-     }
--    if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data)) < 0)
--        return r;
-+    pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data);
--    pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID);
-+    if (data->driver && !pa_utf8_valid(data->driver)) {
-+        r = -PA_ERR_INVALID;
-+        goto fail;
-+    }
-     if (!data->source) {
-         pa_source *source;
-         if (data->direct_on_input) {
-             source = data->direct_on_input->sink->monitor_source;
--            pa_return_val_if_fail(source, -PA_ERR_INVALID);
-+            if (!source) {
-+                r = -PA_ERR_INVALID;
-+                goto fail;
-+            }
-         } else {
-             source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE);
--            pa_return_val_if_fail(source, -PA_ERR_NOENTITY);
-+            if (!source) {
-+                r = -PA_ERR_NOENTITY;
-+                goto fail;
-+            }
-         }
-         pa_source_output_new_data_set_source(data, source, false);
-@@ -324,11 +337,19 @@ int pa_source_output_new(
-         PA_IDXSET_FOREACH(format, data->req_formats, idx)
-             pa_log_info(" -- %s", pa_format_info_snprint(fmt, sizeof(fmt), format));
--        return -PA_ERR_NOTSUPPORTED;
-+        r = -PA_ERR_NOTSUPPORTED;
-+        goto fail;
-     }
--    pa_return_val_if_fail(PA_SOURCE_IS_LINKED(pa_source_get_state(data->source)), -PA_ERR_BADSTATE);
--    pa_return_val_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of, -PA_ERR_INVALID);
-+    if (!PA_SOURCE_IS_LINKED(pa_source_get_state(data->source))) {
-+        r = -PA_ERR_BADSTATE;
-+        goto fail;
-+    }
-+
-+    if (data->direct_on_input && data->direct_on_input->sink != data->source->monitor_of) {
-+        r = -PA_ERR_INVALID;
-+        goto fail;
-+    }
-     /* Routing is done. We have a source and a format. */
-@@ -339,7 +360,7 @@ int pa_source_output_new(
-          * modified in pa_format_info_to_sample_spec2(). */
-         r = pa_stream_get_volume_channel_map(&data->volume, data->channel_map_is_set ? &data->channel_map : NULL, data->format, &volume_map);
-         if (r < 0)
--            return r;
-+            goto fail;
-     }
-     /* Now populate the sample spec and channel map according to the final
-@@ -347,7 +368,7 @@ int pa_source_output_new(
-     r = pa_format_info_to_sample_spec2(data->format, &data->sample_spec, &data->channel_map, &data->source->sample_spec,
-                                        &data->source->channel_map);
-     if (r < 0)
--        return r;
-+        goto fail;
-     /* Now that the routing is done, we can finalize the volume if it has been
-      * set. If the set volume is relative, we convert it to absolute, and if
-@@ -374,12 +395,18 @@ int pa_source_output_new(
-     if (!data->volume_factor_is_set)
-         pa_cvolume_reset(&data->volume_factor, data->sample_spec.channels);
--    pa_return_val_if_fail(pa_cvolume_compatible(&data->volume_factor, &data->sample_spec), -PA_ERR_INVALID);
-+    if (!pa_cvolume_compatible(&data->volume_factor, &data->sample_spec)) {
-+        r = -PA_ERR_INVALID;
-+        goto fail;
-+    }
-     if (!data->volume_factor_source_is_set)
-         pa_cvolume_reset(&data->volume_factor_source, data->source->sample_spec.channels);
--    pa_return_val_if_fail(pa_cvolume_compatible(&data->volume_factor_source, &data->source->sample_spec), -PA_ERR_INVALID);
-+    if (!pa_cvolume_compatible(&data->volume_factor_source, &data->source->sample_spec)) {
-+        r = -PA_ERR_INVALID;
-+        goto fail;
-+    }
-     if (!data->muted_is_set)
-         data->muted = false;
-@@ -399,16 +426,19 @@ int pa_source_output_new(
-         /* rate update failed, or other parts of sample spec didn't match */
-         pa_log_debug("Could not update source sample spec to match passthrough stream");
--        return -PA_ERR_NOTSUPPORTED;
-+        r = -PA_ERR_NOTSUPPORTED;
-+        goto fail;
-     }
-     if (data->resample_method == PA_RESAMPLER_INVALID)
-         data->resample_method = core->resample_method;
--    pa_return_val_if_fail(data->resample_method < PA_RESAMPLER_MAX, -PA_ERR_INVALID);
-+    if (data->resample_method >= PA_RESAMPLER_MAX) {
-+        r = -PA_ERR_INVALID;
-+        goto fail;
-+    }
--    if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data)) < 0)
--        return r;
-+    pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data);
-     if (!data->volume_is_set) {
-         pa_cvolume_reset(&v, data->sample_spec.channels);
-@@ -419,12 +449,14 @@ int pa_source_output_new(
-     if ((data->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND) &&
-         pa_source_get_state(data->source) == PA_SOURCE_SUSPENDED) {
-         pa_log("Failed to create source output: source is suspended.");
--        return -PA_ERR_BADSTATE;
-+        r = -PA_ERR_BADSTATE;
-+        goto fail;
-     }
-     if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
-         pa_log("Failed to create source output: too many outputs per source.");
--        return -PA_ERR_TOOLARGE;
-+        r = -PA_ERR_TOOLARGE;
-+        goto fail;
-     }
-     if ((data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
-@@ -442,16 +474,15 @@ int pa_source_output_new(
-                         (core->disable_remixing || (data->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
-                         (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) {
-                 pa_log_warn("Unsupported resampling operation.");
--                return -PA_ERR_NOTSUPPORTED;
-+                r = -PA_ERR_NOTSUPPORTED;
-+                goto fail;
-             }
-     }
--    o = pa_msgobject_new(pa_source_output);
-     o->parent.parent.free = source_output_free;
-     o->parent.process_msg = pa_source_output_process_msg;
-     o->core = core;
--    o->state = PA_SOURCE_OUTPUT_INIT;
-     o->flags = data->flags;
-     o->proplist = pa_proplist_copy(data->proplist);
-     o->driver = pa_xstrdup(pa_path_get_filename(data->driver));
-@@ -526,6 +557,16 @@ int pa_source_output_new(
-     *_o = o;
-     return 0;
-+
-+fail:
-+    if (o) {
-+        pa_source_output_unlink(o);
-+        pa_source_output_unref(o);
-+    }
-+
-+    data->source_output = NULL;
-+
-+    return r;
- }
- /* Called from main context */
-@@ -576,9 +617,15 @@ static void source_output_set_state(pa_source_output *o, pa_source_output_state_
- /* Called from main context */
- void pa_source_output_unlink(pa_source_output*o) {
-     bool linked;
-+
-     pa_assert(o);
-     pa_assert_ctl_context();
-+    if (o->unlinked)
-+        return;
-+
-+    o->unlinked = true;
-+
-     /* See pa_sink_unlink() for a couple of comments how this function
-      * works */
-@@ -587,13 +634,13 @@ void pa_source_output_unlink(pa_source_output*o) {
-     linked = PA_SOURCE_OUTPUT_IS_LINKED(o->state);
-     if (linked)
--        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o);
-+        pa_idxset_remove_by_data(o->core->source_outputs, o, NULL);
-+
-+    pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o);
-     if (o->direct_on_input)
-         pa_idxset_remove_by_data(o->direct_on_input->direct_outputs, o, NULL);
--    pa_idxset_remove_by_data(o->core->source_outputs, o, NULL);
--
-     if (o->source)
-         if (pa_idxset_remove_by_data(o->source->outputs, o, NULL))
-             pa_source_output_unref(o);
-@@ -618,10 +665,10 @@ void pa_source_output_unlink(pa_source_output*o) {
-     reset_callbacks(o);
--    if (linked) {
-+    if (linked)
-         pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index);
--        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o);
--    }
-+
-+    pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o);
-     if (o->source) {
-         if (PA_SOURCE_IS_LINKED(pa_source_get_state(o->source)))
-diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
-index dc82af9..af6d347 100644
---- a/src/pulsecore/source-output.h
-+++ b/src/pulsecore/source-output.h
-@@ -69,6 +69,7 @@ struct pa_source_output {
-     pa_core *core;
-     pa_source_output_state_t state;
-+    bool unlinked;
-     pa_source_output_flags_t flags;
-     char *driver;                         /* may be NULL */
-@@ -236,6 +237,11 @@ typedef struct pa_source_output_send_event_hook_data {
- } pa_source_output_send_event_hook_data;
- typedef struct pa_source_output_new_data {
-+    /* The source output object is not properly initialized, so don't access
-+     * the member variables! You can only rely on the state variable being
-+     * initialized to PA_SOURCE_OUTPUT_INIT. */
-+    pa_source_output *source_output;
-+
-     pa_source_output_flags_t flags;
-     pa_proplist *proplist;
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0103-audio-groups-main-volume-policy-volume-api-Various-f.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/0103-audio-groups-main-volume-policy-volume-api-Various-f.patch
deleted file mode 100644 (file)
index 626d911..0000000
+++ /dev/null
@@ -1,9676 +0,0 @@
-From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com>
-Date: Tue, 17 Jun 2014 19:45:45 +0300
-Subject: audio-groups, main-volume-policy, volume-api: Various fixes
-
-Sorry, this is a huge unreviewable commit. Contained improvements
-include at least:
-
- * Flat volumes are now handled properly. Previously, audio groups
-   controlled the absolute volume of streams if flat volume was in
-   effect, which made no sense.
- * Audio group volumes are now persistent.
- * Audio group volumes are applied to new streams before the streams
-   start to play, instead of after, which could cause audible
-   glitches.
- * When a stream volume is changed by the user, the volume is
-   propagated to the stream's audio group.
- * Fixed the handling of the "NEG" keyword in the match syntax in
-   module-audio-groups. Previously the "NEG" keyword was parsed, but
-   it had no effect.
-
-Change-Id: I02bad3d23b3e562c71dbc6af6f3e308089893751
----
- src/Makefile.am                                    |    2 +-
- src/map-file                                       |    3 +
- src/modules/audio-groups/audio-groups.conf.example |   19 +-
- src/modules/audio-groups/module-audio-groups.c     | 1710 ++++++++++++++------
- .../main-volume-policy/main-volume-context.c       |  184 +--
- .../main-volume-policy/main-volume-context.h       |   35 +-
- .../main-volume-policy/main-volume-policy.c        |   65 +-
- .../main-volume-policy.conf.example                |    1 -
- .../main-volume-policy/main-volume-policy.h        |    6 +-
- .../main-volume-policy/module-main-volume-policy.c |  651 +++++---
- src/modules/volume-api/audio-group.c               |  288 +---
- src/modules/volume-api/audio-group.h               |   29 +-
- src/modules/volume-api/binding.c                   |  386 -----
- src/modules/volume-api/binding.h                   |  128 --
- src/modules/volume-api/bvolume.h                   |    3 +
- src/modules/volume-api/device-creator.c            |  431 +++--
- src/modules/volume-api/device.c                    |   54 +-
- src/modules/volume-api/device.h                    |    4 +-
- src/modules/volume-api/inidb.c                     |  553 +++++++
- src/modules/volume-api/inidb.h                     |   54 +
- src/modules/volume-api/module-volume-api.c         |   27 +
- src/modules/volume-api/mute-control.c              |  241 +--
- src/modules/volume-api/mute-control.h              |   75 +-
- src/modules/volume-api/sstream.c                   |  313 ++--
- src/modules/volume-api/sstream.h                   |   56 +-
- src/modules/volume-api/stream-creator.c            |  691 ++++----
- src/modules/volume-api/volume-api.c                |  430 +++--
- src/modules/volume-api/volume-api.h                |   79 +-
- src/modules/volume-api/volume-control.c            |  308 ++--
- src/modules/volume-api/volume-control.h            |   93 +-
- src/pulse/ext-volume-api.c                         |  100 ++
- src/pulse/ext-volume-api.h                         |    3 +
- src/tizen-ivi/audio-groups.conf                    |   23 +-
- src/tizen-ivi/main-volume-policy.conf              |    1 -
- 34 files changed, 4012 insertions(+), 3034 deletions(-)
- delete mode 100644 src/modules/volume-api/binding.c
- delete mode 100644 src/modules/volume-api/binding.h
- create mode 100644 src/modules/volume-api/inidb.c
- create mode 100644 src/modules/volume-api/inidb.h
-
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 9d17336..b5cf2a8 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -1098,10 +1098,10 @@ 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/inidb.c modules/volume-api/inidb.h \
-               modules/volume-api/mute-control.c modules/volume-api/mute-control.h \
-               modules/volume-api/sstream.c modules/volume-api/sstream.h \
-               modules/volume-api/stream-creator.c modules/volume-api/stream-creator.h \
-diff --git a/src/map-file b/src/map-file
-index 28ea54e..cb31833 100644
---- a/src/map-file
-+++ b/src/map-file
-@@ -190,13 +190,16 @@ pa_ext_node_manager_set_subscribe_cb;
- pa_ext_echo_cancel_set_volume;
- pa_ext_echo_cancel_set_device;
- pa_ext_volume_api_balance_valid;
-+pa_ext_volume_api_bvolume_balance_to_string;
- 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;
- pa_ext_volume_api_bvolume_init_invalid;
- pa_ext_volume_api_bvolume_init_mono;
-+pa_ext_volume_api_bvolume_parse_balance;
- pa_ext_volume_api_bvolume_remap;
- pa_ext_volume_api_bvolume_reset_balance;
- pa_ext_volume_api_bvolume_set_left_right_balance;
-diff --git a/src/modules/audio-groups/audio-groups.conf.example b/src/modules/audio-groups/audio-groups.conf.example
-index 8acdb76..6aa6989 100644
---- a/src/modules/audio-groups/audio-groups.conf.example
-+++ b/src/modules/audio-groups/audio-groups.conf.example
-@@ -1,28 +1,29 @@
- [General]
--audio-groups = x-example-call-downlink-audio-group x-example-default-output-audio-group x-example-music-output-audio-group
--streams = phone-output music-output default-output
-+stream-rules = phone-output music-output default-output
- [AudioGroup x-example-call-downlink-audio-group]
--volume-control = create
--mute-control = none
-+volume-control = create:call-downlink-volume-control
-+mute-control = create:call-downlink-mute-control
- [AudioGroup x-example-default-output-audio-group]
--volume-control = create
--mute-control = none
-+volume-control = create:default-output-volume-control
-+mute-control = create:call-downlink-mute-control
- [AudioGroup x-example-music-output-audio-group]
- volume-control = bind:AudioGroup:x-example-default-output-audio-group
-+mute-control = bind:AudioGroup:x-example-default-output-audio-group
--[Stream phone-output]
-+[StreamRule phone-output]
- match = (direction output AND property media.role=phone)
- audio-group-for-volume = x-example-call-downlink-audio-group
- audio-group-for-mute = x-example-call-downlink-audio-group
--[Stream music-output]
-+[StreamRule music-output]
- match = (direction output AND property media.role=music)
- audio-group-for-volume = x-example-music-output-audio-group
- audio-group-for-mute = x-example-music-output-audio-group
--[Stream default-output]
-+[StreamRule default-output]
-+match = (direction output)
- audio-group-for-volume = x-example-default-output-audio-group
- audio-group-for-mute = x-example-default-output-audio-group
-diff --git a/src/modules/audio-groups/module-audio-groups.c b/src/modules/audio-groups/module-audio-groups.c
-index 2b3a570..e37a24e 100644
---- a/src/modules/audio-groups/module-audio-groups.c
-+++ b/src/modules/audio-groups/module-audio-groups.c
-@@ -40,15 +40,18 @@
- #include "module-audio-groups-symdef.h"
-+#define AUDIOGROUP_START "AudioGroup "
-+#define STREAM_RULE_START "StreamRule "
-+#define NONE_KEYWORD "none"
-+#define CREATE_PREFIX "create:"
-+#define BIND_PREFIX "bind:"
-+#define BIND_AUDIO_GROUP_PREFIX BIND_PREFIX "AudioGroup:"
-+
- PA_MODULE_AUTHOR("Ismo Puustinen");
- PA_MODULE_DESCRIPTION("Create audio groups and classify streams to them");
- PA_MODULE_VERSION(PACKAGE_VERSION);
- PA_MODULE_LOAD_ONCE(true);
--#ifndef AUDIO_GROUP_CONFIG
--#define AUDIO_GROUP_CONFIG "audio-groups.conf"
--#endif
--
- enum match_direction {
-     match_direction_unknown = 0,
-     match_direction_input,
-@@ -80,60 +83,103 @@ struct expression {
-     PA_LLIST_HEAD(struct conjunction, conjunctions);
- };
--/* data gathered from settings */
-+struct group {
-+    struct userdata *userdata;
-+    pa_audio_group *audio_group;
-+    struct control *volume_control;
-+    struct control *mute_control;
-+    char *own_volume_control_name;
-+    char *own_mute_control_name;
-+    struct group *volume_master;
-+    struct group *mute_master;
-+    char *volume_master_name;
-+    char *mute_master_name;
-+
-+    pa_hashmap *volume_slaves; /* struct group -> struct group (hashmap-as-a-set) */
-+    pa_hashmap *mute_slaves; /* struct group -> struct group (hashmap-as-a-set) */
-+    pa_hashmap *volume_stream_rules; /* struct stream_rule -> struct stream_rule (hashmap-as-a-set) */
-+    pa_hashmap *mute_stream_rules; /* struct stream_rule -> struct stream_rule (hashmap-as-a-set) */
-+
-+    bool unlinked;
-+};
--enum control_action {
--    CONTROL_ACTION_NONE,
--    CONTROL_ACTION_CREATE,
--    CONTROL_ACTION_BIND,
-+enum control_type {
-+    CONTROL_TYPE_VOLUME,
-+    CONTROL_TYPE_MUTE,
- };
--struct audio_group {
-+struct control {
-     struct userdata *userdata;
--    char *id;
--    char *description;
--    enum control_action volume_control_action;
--    enum control_action mute_control_action;
--    pa_binding_target_info *volume_control_target_info;
--    pa_binding_target_info *mute_control_target_info;
-+    enum control_type type;
-+
-+    union {
-+        pa_volume_control *volume_control;
-+        pa_mute_control *mute_control;
-+    };
-+
-+    /* Controls that are created for streams don't own their pa_volume_control
-+     * and pa_mute_control objects, because they're owned by the streams. */
-+    bool own_control;
--    /* official audio group */
--    pa_audio_group *group;
-+    /* If non-NULL, then this control mirrors the state of the master
-+     * control. If someone changes the master state, the state of this control
-+     * is also updated, and also if someone changes this control's state, the
-+     * change is applied also to the master. */
-+    struct control *master;
--    struct audio_group_control *volume_control;
--    struct audio_group_control *mute_control;
-+    /* struct control -> struct control (hashmap-as-a-set)
-+     * Contains the controls that have this control as their master. */
-+    pa_hashmap *slaves;
-+    /* Set to true when the master control's state has been copied to this
-+     * control. */
-+    bool synced_with_master;
-+
-+    bool acquired;
-     bool unlinked;
- };
--struct stream {
-+struct stream_rule {
-     struct userdata *userdata;
--    char *id;
-+    char *name;
-     enum match_direction direction;
-     char *audio_group_name_for_volume;
-     char *audio_group_name_for_mute;
--    pa_audio_group *audio_group_for_volume;
--    pa_audio_group *audio_group_for_mute;
--    pa_binding_target_info *volume_control_target_info;
--    pa_binding_target_info *mute_control_target_info;
--    struct expression *rule;
--
--    bool unlinked;
-+    struct group *group_for_volume;
-+    struct group *group_for_mute;
-+    struct expression *match_expression;
- };
- struct userdata {
--    pa_hashmap *audio_groups; /* name -> struct audio_group */
--    pa_dynarray *streams; /* struct stream */
--    pa_hook_slot *new_stream_volume;
--    pa_hook_slot *new_stream_mute;
--
--    pa_volume_api *api;
--
--    /* The following fields are only used during initialization. */
--    pa_hashmap *audio_group_names; /* name -> name (hashmap-as-a-set) */
--    pa_hashmap *unused_audio_groups; /* name -> struct audio_group */
--    pa_dynarray *stream_names;
--    pa_hashmap *unused_streams; /* name -> struct stream */
-+    pa_volume_api *volume_api;
-+    pa_hashmap *groups; /* name -> struct group */
-+    pa_hashmap *stream_rules; /* name -> struct stream_rule */
-+    pa_dynarray *stream_rules_list; /* struct stream_rule */
-+
-+    /* pas_stream -> struct stream_rule
-+     * When a stream matches with a rule, it's added here. */
-+    pa_hashmap *rules_by_stream;
-+
-+    /* pas_stream -> struct control
-+     * Contains proxy controls for all relative volume controls of streams. */
-+    pa_hashmap *stream_volume_controls;
-+
-+    /* pas_stream -> struct control
-+     * Contains proxy controls for all mute controls of streams. */
-+    pa_hashmap *stream_mute_controls;
-+
-+    pa_hook_slot *stream_put_slot;
-+    pa_hook_slot *stream_unlink_slot;
-+    pa_hook_slot *volume_control_implementation_initialized_slot;
-+    pa_hook_slot *mute_control_implementation_initialized_slot;
-+    pa_hook_slot *volume_control_set_initial_volume_slot;
-+    pa_hook_slot *mute_control_set_initial_mute_slot;
-+    pa_hook_slot *volume_control_volume_changed_slot;
-+    pa_hook_slot *mute_control_mute_changed_slot;
-+    pa_hook_slot *volume_control_unlink_slot;
-+    pa_hook_slot *mute_control_unlink_slot;
-+
-+    pa_dynarray *stream_rule_names; /* Only used during initialization. */
- };
- static const char* const valid_modargs[] = {
-@@ -141,77 +187,408 @@ static const char* const valid_modargs[] = {
-     NULL
- };
--static void audio_group_unlink(struct audio_group *group);
-+static void control_free(struct control *control);
-+static void control_set_master(struct control *control, struct control *master);
-+static void control_add_slave(struct control *control, struct control *slave);
-+static void control_remove_slave(struct control *control, struct control *slave);
--static void print_literal(struct literal *l);
--static void print_conjunction(struct conjunction *c);
--static void print_expression(struct expression *e);
--static void delete_expression(struct expression *e);
-+static void group_free(struct group *group);
-+static void group_set_master(struct group *group, enum control_type type, struct group *master);
-+static int group_set_master_name(struct group *group, enum control_type type, const char *name);
-+static void group_disable_control(struct group *group, enum control_type type);
-+static void group_add_slave(struct group *group, enum control_type type, struct group *slave);
-+static void group_remove_slave(struct group *group, enum control_type type, struct group *slave);
--static struct audio_group *audio_group_new(struct userdata *u, const char *name) {
--    struct audio_group *group;
-+static void stream_rule_set_group(struct stream_rule *rule, enum control_type type, struct group *group);
-+static void stream_rule_set_group_name(struct stream_rule *rule, enum control_type type, const char *name);
--    pa_assert(u);
--    pa_assert(name);
-+static bool literal_match(struct literal *literal, pas_stream *stream);
--    group = pa_xnew0(struct audio_group, 1);
--    group->userdata = u;
--    group->id = pa_xstrdup(name);
--    group->description = pa_xstrdup(name);
--    group->volume_control_action = CONTROL_ACTION_NONE;
--    group->mute_control_action = CONTROL_ACTION_NONE;
-+static struct expression *expression_new(void);
-+static void expression_free(struct expression *expression);
-+
-+static int volume_control_set_volume_cb(pa_volume_control *volume_control, const pa_bvolume *original_volume,
-+                                        const pa_bvolume *remapped_volume, bool set_volume, bool set_balance) {
-+    struct control *control;
-+    struct control *slave;
-+    void *state;
-+
-+    pa_assert(volume_control);
-+    pa_assert(original_volume);
-+    pa_assert(remapped_volume);
-+
-+    control = volume_control->userdata;
-+
-+    /* There are four cases that need to be considered:
-+     *
-+     * 1) The master control is propagating the volume to this control. We need
-+     * to propagate the volume downstream.
-+     *
-+     * 2) This control was just assigned a master control and the volume hasn't
-+     * yet been synchronized. In this case the volume that is now being set for
-+     * this control is the master control's volume. We need to propagate the
-+     * volume downstream.
-+     *
-+     * 3) Someone set the volume directly for this control, and this control
-+     * has a master control. We need to propagate the volume upstream, and wait
-+     * for another call that will fall under the case 1.
-+     *
-+     * 4) Someone set the volume directly for this control, and this control
-+     * doesn't have a master control. We need to propagate the volume
-+     * downstream.
-+     *
-+     * As we can see, the action is the same in cases 1, 2 and 4. */
-+
-+    /* Case 3. */
-+    if (control->synced_with_master && !control->master->volume_control->set_volume_in_progress) {
-+        pa_volume_control_set_volume(control->master->volume_control, original_volume, set_volume, set_balance);
-+        return 0;
-+    }
-+
-+    /* Cases 1, 2 and 4. */
-+    PA_HASHMAP_FOREACH(slave, control->slaves, state)
-+        pa_volume_control_set_volume(slave->volume_control, original_volume, set_volume, set_balance);
--    return group;
-+    return 0;
- }
--static int audio_group_put(struct audio_group *group) {
--    int r;
-+static int mute_control_set_mute_cb(pa_mute_control *mute_control, bool mute) {
-+    struct control *control;
-+    struct control *slave;
-+    void *state;
-+
-+    pa_assert(mute_control);
-+
-+    control = mute_control->userdata;
-+
-+    /* There are four cases that need to be considered:
-+     *
-+     * 1) The master control is propagating the mute to this control. We need
-+     * to propagate the mute downstream.
-+     *
-+     * 2) This control was just assigned a master control and the mute hasn't
-+     * yet been synchronized. In this case the mute that is now being set for
-+     * this control is the master control's mute. We need to propagate the mute
-+     * downstream.
-+     *
-+     * 3) Someone set the mute directly for this control, and this control has
-+     * a master control. We need to propagate the mute upstream, and wait for
-+     * another call that will fall under the case 1.
-+     *
-+     * 4) Someone set the mute directly for this control, and this control
-+     * doesn't have a master control. We need to propagate the mute downstream.
-+     *
-+     * As we can see, the action is the same in cases 1, 2 and 4. */
-+
-+    /* Case 3. */
-+    if (control->synced_with_master && !control->master->mute_control->set_mute_in_progress) {
-+        pa_mute_control_set_mute(control->master->mute_control, mute);
-+        return 0;
-+    }
-+
-+    /* Cases 1, 2 and 4. */
-+    PA_HASHMAP_FOREACH(slave, control->slaves, state)
-+        pa_mute_control_set_mute(slave->mute_control, mute);
-+
-+    return 0;
-+}
-+
-+static int control_new_for_group(struct group *group, enum control_type type, const char *name, bool persistent, struct control **_r) {
-+    struct control *control = NULL;
-+    int r = 0;
-     pa_assert(group);
-+    pa_assert(name);
-+    pa_assert(_r);
-+
-+    control = pa_xnew0(struct control, 1);
-+    control->userdata = group->userdata;
-+    control->type = type;
-+    control->slaves = pa_hashmap_new(NULL, NULL);
-+
-+    switch (type) {
-+        case CONTROL_TYPE_VOLUME:
-+            if (persistent)
-+                control->volume_control = pa_hashmap_get(control->userdata->volume_api->volume_controls, name);
-+
-+            if (!control->volume_control) {
-+                r = pa_volume_control_new(control->userdata->volume_api, name, persistent, &control->volume_control);
-+                if (r < 0)
-+                    goto fail;
-+            }
--    r = pa_audio_group_new(group->userdata->api, group->id, group->description, &group->group);
--    if (r < 0)
--        goto fail;
-+            pa_volume_control_set_convertible_to_dB(control->volume_control, true);
-+
-+            if (persistent) {
-+                r = pa_volume_control_acquire_for_audio_group(control->volume_control, group->audio_group,
-+                                                              volume_control_set_volume_cb, control);
-+                if (r < 0)
-+                    goto fail;
-+
-+                control->acquired = true;
-+            } else {
-+                control->volume_control->set_volume = volume_control_set_volume_cb;
-+                control->volume_control->userdata = control;
-+            }
-+            break;
-+
-+        case CONTROL_TYPE_MUTE:
-+            if (persistent)
-+                control->mute_control = pa_hashmap_get(control->userdata->volume_api->mute_controls, name);
-+
-+            if (!control->mute_control) {
-+                r = pa_mute_control_new(control->userdata->volume_api, name, persistent, &control->mute_control);
-+                if (r < 0)
-+                    goto fail;
-+            }
-+
-+            if (persistent) {
-+                r = pa_mute_control_acquire_for_audio_group(control->mute_control, group->audio_group,
-+                                                            mute_control_set_mute_cb, control);
-+                if (r < 0)
-+                    goto fail;
-+
-+                control->acquired = true;
-+            } else {
-+                control->mute_control->set_mute = mute_control_set_mute_cb;
-+                control->mute_control->userdata = control;
-+            }
-+            break;
-+    }
-+
-+    control->own_control = true;
-+
-+    *_r = control;
-+    return 0;
-+
-+fail:
-+    if (control)
-+        control_free(control);
-+
-+    return r;
-+}
-+
-+static struct control *control_new_for_stream(struct userdata *u, enum control_type type, pas_stream *stream) {
-+    struct control *control;
-+
-+    pa_assert(u);
-+    pa_assert(stream);
--    switch (group->volume_control_action) {
--        case CONTROL_ACTION_NONE:
-+    control = pa_xnew0(struct control, 1);
-+    control->userdata = u;
-+    control->type = type;
-+
-+    switch (type) {
-+        case CONTROL_TYPE_VOLUME:
-+            control->volume_control = stream->relative_volume_control;
-+            pa_assert(control->volume_control);
-+            break;
-+
-+        case CONTROL_TYPE_MUTE:
-+            control->mute_control = stream->mute_control;
-+            pa_assert(control->mute_control);
-             break;
-+    }
--        case CONTROL_ACTION_CREATE:
--            pa_audio_group_set_have_own_volume_control(group->group, true);
--            pa_audio_group_set_volume_control(group->group, group->group->own_volume_control);
-+    return control;
-+}
-+
-+static void control_put(struct control *control) {
-+    pa_assert(control);
-+
-+    switch (control->type) {
-+        case CONTROL_TYPE_VOLUME:
-+            if (control->own_control && !control->volume_control->linked)
-+                pa_volume_control_put(control->volume_control);
-             break;
--        case CONTROL_ACTION_BIND:
--            pa_audio_group_bind_volume_control(group->group, group->volume_control_target_info);
-+        case CONTROL_TYPE_MUTE:
-+            if (control->own_control && !control->mute_control->linked)
-+                pa_mute_control_put(control->mute_control);
-             break;
-     }
-+}
-+
-+static void control_unlink(struct control *control) {
-+    pa_assert(control);
-+
-+    if (control->unlinked)
-+        return;
-+
-+    control->unlinked = true;
-+
-+    if (control->slaves) {
-+        struct control *slave;
-+
-+        while ((slave = pa_hashmap_first(control->slaves)))
-+            control_set_master(slave, NULL);
-+    }
-+
-+    control_set_master(control, NULL);
--    switch (group->mute_control_action) {
--        case CONTROL_ACTION_NONE:
-+    switch (control->type) {
-+        case CONTROL_TYPE_VOLUME:
-+            if (control->own_control && control->volume_control && !control->volume_control->persistent)
-+                pa_volume_control_unlink(control->volume_control);
-             break;
--        case CONTROL_ACTION_CREATE:
--            pa_audio_group_set_have_own_mute_control(group->group, true);
--            pa_audio_group_set_mute_control(group->group, group->group->own_mute_control);
-+        case CONTROL_TYPE_MUTE:
-+            if (control->own_control && control->mute_control && !control->mute_control->persistent)
-+                pa_mute_control_unlink(control->mute_control);
-             break;
-+    }
-+}
-+
-+static void control_free(struct control *control) {
-+    pa_assert(control);
-+
-+    if (!control->unlinked)
-+        control_unlink(control);
-+
-+    if (control->slaves) {
-+        pa_assert(pa_hashmap_isempty(control->slaves));
-+        pa_hashmap_free(control->slaves);
-+    }
-+
-+    switch (control->type) {
-+        case CONTROL_TYPE_VOLUME:
-+            if (control->acquired)
-+                pa_volume_control_release(control->volume_control);
-+
-+            if (control->own_control && control->volume_control && !control->volume_control->persistent)
-+                pa_volume_control_free(control->volume_control);
-+            break;
-+
-+        case CONTROL_TYPE_MUTE:
-+            if (control->acquired)
-+                pa_mute_control_release(control->mute_control);
--        case CONTROL_ACTION_BIND:
--            pa_audio_group_bind_mute_control(group->group, group->mute_control_target_info);
-+            if (control->own_control && control->mute_control && !control->mute_control->persistent)
-+                pa_mute_control_free(control->mute_control);
-             break;
-     }
--    pa_audio_group_put(group->group);
-+    pa_xfree(control);
-+}
-+
-+static void control_set_master(struct control *control, struct control *master) {
-+    struct control *old_master;
-+
-+    pa_assert(control);
-+    pa_assert(!master || master->type == control->type);
-+
-+    old_master = control->master;
-+
-+    if (master == old_master)
-+        return;
-+
-+    if (old_master) {
-+        control_remove_slave(old_master, control);
-+        control->synced_with_master = false;
-+    }
-+
-+    control->master = master;
-+
-+    if (master) {
-+        control_add_slave(master, control);
-+
-+        switch (control->type) {
-+            case CONTROL_TYPE_VOLUME:
-+                pa_volume_control_set_volume(control->volume_control, &master->volume_control->volume, true, true);
-+                break;
-+
-+            case CONTROL_TYPE_MUTE:
-+                pa_mute_control_set_mute(control->mute_control, master->mute_control->mute);
-+                break;
-+        }
-+
-+        control->synced_with_master = true;
-+    }
-+}
-+
-+static void control_add_slave(struct control *control, struct control *slave) {
-+    pa_assert(control);
-+    pa_assert(slave);
-+
-+    pa_assert_se(pa_hashmap_put(control->slaves, slave, slave) >= 0);
-+}
-+
-+static void control_remove_slave(struct control *control, struct control *slave) {
-+    pa_assert(control);
-+    pa_assert(slave);
-+
-+    pa_assert_se(pa_hashmap_remove(control->slaves, slave));
-+}
-+
-+static int group_new(struct userdata *u, const char *name, struct group **_r) {
-+    struct group *group = NULL;
-+    int r;
-+    struct group *slave;
-+    struct stream_rule *rule;
-+    void *state;
-+
-+    pa_assert(u);
-+    pa_assert(name);
-+    pa_assert(_r);
-+
-+    group = pa_xnew0(struct group, 1);
-+    group->userdata = u;
-+
-+    r = pa_audio_group_new(u->volume_api, name, &group->audio_group);
-+    if (r < 0)
-+        goto fail;
-+
-+    group->volume_slaves = pa_hashmap_new(NULL, NULL);
-+    group->mute_slaves = pa_hashmap_new(NULL, NULL);
-+    group->volume_stream_rules = pa_hashmap_new(NULL, NULL);
-+    group->mute_stream_rules = pa_hashmap_new(NULL, NULL);
-+
-+    PA_HASHMAP_FOREACH(slave, u->groups, state) {
-+        if (slave == group)
-+            continue;
-+
-+        if (pa_safe_streq(slave->volume_master_name, group->audio_group->name))
-+            group_set_master(slave, CONTROL_TYPE_VOLUME, group);
-+
-+        if (pa_safe_streq(slave->mute_master_name, group->audio_group->name))
-+            group_set_master(slave, CONTROL_TYPE_MUTE, group);
-+    }
-+
-+    PA_HASHMAP_FOREACH(rule, u->stream_rules, state) {
-+        if (pa_safe_streq(rule->audio_group_name_for_volume, group->audio_group->name))
-+            stream_rule_set_group(rule, CONTROL_TYPE_VOLUME, group);
-+        if (pa_safe_streq(rule->audio_group_name_for_mute, group->audio_group->name))
-+            stream_rule_set_group(rule, CONTROL_TYPE_MUTE, group);
-+    }
-+
-+    *_r = group;
-     return 0;
- fail:
--    audio_group_unlink(group);
-+    if (group)
-+        group_free(group);
-     return r;
- }
--static void audio_group_unlink(struct audio_group *group) {
-+static void group_put(struct group *group) {
-+    pa_assert(group);
-+
-+    pa_audio_group_put(group->audio_group);
-+
-+    if (group->volume_control)
-+        control_put(group->volume_control);
-+
-+    if (group->mute_control)
-+        control_put(group->mute_control);
-+}
-+
-+static void group_unlink(struct group *group) {
-+    struct stream_rule *rule;
-+    struct group *slave;
-+    void *state;
-+
-     pa_assert(group);
-     if (group->unlinked)
-@@ -219,192 +596,406 @@ static void audio_group_unlink(struct audio_group *group) {
-     group->unlinked = true;
--    if (group->group) {
--        pa_audio_group_free(group->group);
--        group->group = NULL;
--    }
-+    PA_HASHMAP_FOREACH(rule, group->volume_stream_rules, state)
-+        stream_rule_set_group(rule, CONTROL_TYPE_VOLUME, NULL);
-+
-+    PA_HASHMAP_FOREACH(rule, group->mute_stream_rules, state)
-+        stream_rule_set_group(rule, CONTROL_TYPE_MUTE, NULL);
-+
-+    PA_HASHMAP_FOREACH(slave, group->volume_slaves, state)
-+        group_set_master(slave, CONTROL_TYPE_VOLUME, NULL);
-+
-+    PA_HASHMAP_FOREACH(slave, group->mute_slaves, state)
-+        group_set_master(slave, CONTROL_TYPE_MUTE, NULL);
-+
-+    group_disable_control(group, CONTROL_TYPE_MUTE);
-+    group_disable_control(group, CONTROL_TYPE_VOLUME);
-+
-+    if (group->audio_group)
-+        pa_audio_group_unlink(group->audio_group);
- }
--static void audio_group_free(struct audio_group *group) {
-+static void group_free(struct group *group) {
-     pa_assert(group);
--    if (!group->unlinked)
--        audio_group_unlink(group);
-+    group_unlink(group);
-+
-+    if (group->mute_stream_rules) {
-+        pa_assert(pa_hashmap_isempty(group->mute_stream_rules));
-+        pa_hashmap_free(group->mute_stream_rules);
-+    }
-+
-+    if (group->volume_stream_rules) {
-+        pa_assert(pa_hashmap_isempty(group->volume_stream_rules));
-+        pa_hashmap_free(group->volume_stream_rules);
-+    }
-+
-+    if (group->mute_slaves) {
-+        pa_assert(pa_hashmap_isempty(group->mute_slaves));
-+        pa_hashmap_free(group->mute_slaves);
-+    }
-+
-+    if (group->volume_slaves) {
-+        pa_assert(pa_hashmap_isempty(group->volume_slaves));
-+        pa_hashmap_free(group->volume_slaves);
-+    }
--    if (group->mute_control_target_info)
--        pa_binding_target_info_free(group->mute_control_target_info);
-+    pa_assert(!group->mute_master_name);
-+    pa_assert(!group->volume_master_name);
-+    pa_assert(!group->mute_master);
-+    pa_assert(!group->volume_master);
-+    pa_assert(!group->mute_control);
-+    pa_assert(!group->volume_control);
--    if (group->volume_control_target_info)
--        pa_binding_target_info_free(group->volume_control_target_info);
-+    if (group->audio_group)
-+        pa_audio_group_free(group->audio_group);
--    pa_xfree(group->description);
--    pa_xfree(group->id);
-     pa_xfree(group);
- }
--static void audio_group_set_description(struct audio_group *group, const char *description) {
-+static void group_set_own_control_name(struct group *group, enum control_type type, const char *name) {
-+    struct group *slave;
-+    void *state;
-+
-     pa_assert(group);
--    pa_assert(description);
--    pa_xfree(group->description);
--    group->description = pa_xstrdup(description);
-+    if (name)
-+        group_set_master_name(group, type, NULL);
-+
-+    switch (type) {
-+        case CONTROL_TYPE_VOLUME:
-+            if (pa_safe_streq(name, group->own_volume_control_name))
-+                return;
-+
-+            if (group->volume_control) {
-+                control_free(group->volume_control);
-+                group->volume_control = NULL;
-+            }
-+
-+            pa_xfree(group->own_volume_control_name);
-+            group->own_volume_control_name = pa_xstrdup(name);
-+
-+            if (name) {
-+                control_new_for_group(group, CONTROL_TYPE_VOLUME, name, true, &group->volume_control);
-+
-+                PA_HASHMAP_FOREACH(slave, group->volume_slaves, state) {
-+                    if (slave->volume_control)
-+                        control_set_master(slave->volume_control, group->volume_control);
-+                }
-+            }
-+            break;
-+
-+        case CONTROL_TYPE_MUTE:
-+            if (pa_safe_streq(name, group->own_mute_control_name))
-+                return;
-+
-+            if (group->mute_control) {
-+                control_free(group->mute_control);
-+                group->mute_control = NULL;
-+            }
-+
-+            pa_xfree(group->own_mute_control_name);
-+            group->own_mute_control_name = pa_xstrdup(name);
-+
-+            if (name) {
-+                control_new_for_group(group, CONTROL_TYPE_MUTE, name, true, &group->mute_control);
-+
-+                PA_HASHMAP_FOREACH(slave, group->mute_slaves, state) {
-+                    if (slave->mute_control)
-+                        control_set_master(slave->mute_control, group->mute_control);
-+                }
-+            }
-+            break;
-+    }
- }
--static void audio_group_set_volume_control_action(struct audio_group *group, enum control_action action,
--                                                  pa_binding_target_info *target_info) {
-+static void group_set_master(struct group *group, enum control_type type, struct group *master) {
-+    struct group *old_master;
-+    struct control *master_control = NULL;
-+
-     pa_assert(group);
--    pa_assert((action == CONTROL_ACTION_BIND) ^ !target_info);
-+    pa_assert(master != group);
-+
-+    switch (type) {
-+        case CONTROL_TYPE_VOLUME:
-+            old_master = group->volume_master;
-+
-+            if (master == old_master)
-+                return;
-+
-+            if (old_master)
-+                group_remove_slave(old_master, CONTROL_TYPE_VOLUME, group);
-+
-+            group->volume_master = master;
-+
-+            if (master)
-+                group_add_slave(master, CONTROL_TYPE_VOLUME, group);
-+
-+            if (group->volume_control) {
-+                if (master)
-+                    master_control = master->volume_control;
--    group->volume_control_action = action;
-+                control_set_master(group->volume_control, master_control);
-+            }
-+            break;
-+
-+        case CONTROL_TYPE_MUTE:
-+            old_master = group->mute_master;
-+
-+            if (master == old_master)
-+                return;
--    if (group->volume_control_target_info)
--        pa_binding_target_info_free(group->volume_control_target_info);
-+            if (old_master)
-+                group_remove_slave(old_master, CONTROL_TYPE_MUTE, group);
--    if (action == CONTROL_ACTION_BIND)
--        group->volume_control_target_info = pa_binding_target_info_copy(target_info);
--    else
--        group->volume_control_target_info = NULL;
-+            group->mute_master = master;
-+
-+            if (master)
-+                group_add_slave(master, CONTROL_TYPE_MUTE, group);
-+
-+            if (group->mute_control) {
-+                if (master)
-+                    master_control = master->volume_control;
-+
-+                control_set_master(group->volume_control, master_control);
-+            }
-+            break;
-+    }
- }
--static void audio_group_set_mute_control_action(struct audio_group *group, enum control_action action,
--                                                pa_binding_target_info *target_info) {
-+static int group_set_master_name(struct group *group, enum control_type type, const char *name) {
-+    struct group *slave;
-+    void *state;
-+    struct group *master = NULL;
-+
-     pa_assert(group);
--    pa_assert((action == CONTROL_ACTION_BIND) ^ !target_info);
--    group->mute_control_action = action;
-+    if (pa_safe_streq(name, group->audio_group->name)) {
-+        pa_log("Can't bind audio group control to itself.");
-+        return -PA_ERR_INVALID;
-+    }
--    if (group->mute_control_target_info)
--        pa_binding_target_info_free(group->mute_control_target_info);
-+    if (name)
-+        group_set_own_control_name(group, type, NULL);
--    if (action == CONTROL_ACTION_BIND)
--        group->mute_control_target_info = pa_binding_target_info_copy(target_info);
--    else
--        group->mute_control_target_info = NULL;
--}
-+    switch (type) {
-+        case CONTROL_TYPE_VOLUME:
-+            if (pa_safe_streq(name, group->volume_master_name))
-+                return 0;
--static struct stream *stream_new(struct userdata *u, const char *name) {
--    struct stream *stream;
-+            pa_xfree(group->volume_master_name);
-+            group->volume_master_name = pa_xstrdup(name);
--    pa_assert(u);
--    pa_assert(name);
-+            if (name && !group->volume_control) {
-+                control_new_for_group(group, CONTROL_TYPE_VOLUME, "audio-group-volume-control", false, &group->volume_control);
--    stream = pa_xnew0(struct stream, 1);
--    stream->userdata = u;
--    stream->id = pa_xstrdup(name);
--    stream->direction = match_direction_unknown;
-+                PA_HASHMAP_FOREACH(slave, group->volume_slaves, state) {
-+                    if (slave->volume_control)
-+                        control_set_master(slave->volume_control, group->volume_control);
-+                }
--    return stream;
--}
-+            } else if (!name && group->volume_control) {
-+                control_free(group->volume_control);
-+                group->volume_control = NULL;
-+            }
-+            break;
--static void stream_put(struct stream *stream) {
--    pa_assert(stream);
-+        case CONTROL_TYPE_MUTE:
-+            if (pa_safe_streq(name, group->mute_master_name))
-+                return 0;
--    if (stream->audio_group_name_for_volume) {
--        stream->audio_group_for_volume = pa_hashmap_get(stream->userdata->audio_groups, stream->audio_group_name_for_volume);
--        if (stream->audio_group_for_volume)
--            stream->volume_control_target_info =
--                    pa_binding_target_info_new(PA_AUDIO_GROUP_BINDING_TARGET_TYPE, stream->audio_group_for_volume->name,
--                                               PA_AUDIO_GROUP_BINDING_TARGET_FIELD_VOLUME_CONTROL);
--        else
--            pa_log("Stream %s refers to undefined audio group %s.", stream->id, stream->audio_group_name_for_volume);
-+            pa_xfree(group->mute_master_name);
-+            group->mute_master_name = pa_xstrdup(name);
-+
-+            if (name && !group->mute_control) {
-+                control_new_for_group(group, CONTROL_TYPE_MUTE, "audio-group-mute-control", false, &group->mute_control);
-+
-+                PA_HASHMAP_FOREACH(slave, group->mute_slaves, state) {
-+                    if (slave->mute_control)
-+                        control_set_master(slave->mute_control, group->mute_control);
-+                }
-+
-+            } else if (!name && group->mute_control) {
-+                control_free(group->mute_control);
-+                group->mute_control = NULL;
-+            }
-+            break;
-     }
--    if (stream->audio_group_name_for_mute) {
--        stream->audio_group_for_mute = pa_hashmap_get(stream->userdata->audio_groups, stream->audio_group_name_for_mute);
--        if (stream->audio_group_for_mute)
--            stream->mute_control_target_info =
--                    pa_binding_target_info_new(PA_AUDIO_GROUP_BINDING_TARGET_TYPE, stream->audio_group_for_mute->name,
--                                               PA_AUDIO_GROUP_BINDING_TARGET_FIELD_MUTE_CONTROL);
--        else
--            pa_log("Stream %s refers to undefined audio group %s.", stream->id, stream->audio_group_name_for_volume);
-+    if (name)
-+        master = pa_hashmap_get(group->userdata->groups, name);
-+
-+    group_set_master(group, type, master);
-+
-+    return 0;
-+}
-+
-+static void group_disable_control(struct group *group, enum control_type type) {
-+    pa_assert(group);
-+
-+    group_set_own_control_name(group, type, NULL);
-+    group_set_master_name(group, type, NULL);
-+}
-+
-+static void group_add_slave(struct group *group, enum control_type type, struct group *slave) {
-+    pa_assert(group);
-+    pa_assert(slave);
-+
-+    switch (type) {
-+        case CONTROL_TYPE_VOLUME:
-+            pa_assert_se(pa_hashmap_put(group->volume_slaves, slave, slave) >= 0);
-+            break;
-+
-+        case CONTROL_TYPE_MUTE:
-+            pa_assert_se(pa_hashmap_put(group->mute_slaves, slave, slave) >= 0);
-+            break;
-     }
- }
--static void stream_unlink(struct stream *stream) {
--    pa_assert(stream);
-+static void group_remove_slave(struct group *group, enum control_type type, struct group *slave) {
-+    pa_assert(group);
-+    pa_assert(slave);
--    if (stream->unlinked)
--        return;
-+    switch (type) {
-+        case CONTROL_TYPE_VOLUME:
-+            pa_assert_se(pa_hashmap_remove(group->volume_slaves, slave));
-+            break;
--    if (stream->mute_control_target_info) {
--        pa_binding_target_info_free(stream->mute_control_target_info);
--        stream->mute_control_target_info = NULL;
-+        case CONTROL_TYPE_MUTE:
-+            pa_assert_se(pa_hashmap_remove(group->mute_slaves, slave));
-     }
-+}
--    if (stream->volume_control_target_info) {
--        pa_binding_target_info_free(stream->volume_control_target_info);
--        stream->volume_control_target_info = NULL;
-+static void group_add_stream_rule(struct group *group, enum control_type type, struct stream_rule *rule) {
-+    pa_assert(group);
-+    pa_assert(rule);
-+
-+    switch (type) {
-+        case CONTROL_TYPE_VOLUME:
-+            pa_assert_se(pa_hashmap_put(group->volume_stream_rules, rule, rule) >= 0);
-+            break;
-+
-+        case CONTROL_TYPE_MUTE:
-+            pa_assert_se(pa_hashmap_put(group->mute_stream_rules, rule, rule) >= 0);
-+            break;
-     }
-+}
-+
-+static void group_remove_stream_rule(struct group *group, enum control_type type, struct stream_rule *rule) {
-+    pa_assert(group);
-+    pa_assert(rule);
--    stream->unlinked = true;
-+    switch (type) {
-+        case CONTROL_TYPE_VOLUME:
-+            pa_assert_se(pa_hashmap_remove(group->volume_stream_rules, rule));
-+            break;
-+
-+        case CONTROL_TYPE_MUTE:
-+            pa_assert_se(pa_hashmap_remove(group->mute_stream_rules, rule));
-+            break;
-+    }
- }
--static void stream_free(struct stream *stream) {
--    pa_assert(stream);
-+static struct stream_rule *stream_rule_new(struct userdata *u, const char *name) {
-+    struct stream_rule *rule;
--    if (!stream->unlinked)
--        stream_unlink(stream);
-+    pa_assert(u);
-+    pa_assert(name);
--    if (stream->rule)
--        delete_expression(stream->rule);
-+    rule = pa_xnew0(struct stream_rule, 1);
-+    rule->userdata = u;
-+    rule->name = pa_xstrdup(name);
-+    rule->direction = match_direction_unknown;
-+    rule->match_expression = expression_new();
--    pa_xfree(stream->audio_group_name_for_mute);
--    pa_xfree(stream->audio_group_name_for_volume);
--    pa_xfree(stream->id);
--    pa_xfree(stream);
-+    return rule;
- }
--static void stream_set_audio_group_name_for_volume(struct stream *stream, const char *name) {
--    pa_assert(stream);
-+static void stream_rule_free(struct stream_rule *rule) {
-+    pa_assert(rule);
--    pa_xfree(stream->audio_group_name_for_volume);
--    stream->audio_group_name_for_volume = pa_xstrdup(name);
-+    if (rule->match_expression)
-+        expression_free(rule->match_expression);
-+
-+    stream_rule_set_group_name(rule, CONTROL_TYPE_MUTE, NULL);
-+    stream_rule_set_group_name(rule, CONTROL_TYPE_VOLUME, NULL);
-+    pa_xfree(rule->name);
-+    pa_xfree(rule);
- }
--static void stream_set_audio_group_name_for_mute(struct stream *stream, const char *name) {
--    pa_assert(stream);
-+static void stream_rule_set_match_expression(struct stream_rule *rule, struct expression *expression) {
-+    pa_assert(rule);
-+    pa_assert(expression);
--    pa_xfree(stream->audio_group_name_for_mute);
--    stream->audio_group_name_for_mute = pa_xstrdup(name);
-+    if (rule->match_expression)
-+        expression_free(rule->match_expression);
-+
-+    rule->match_expression = expression;
- }
--/* stream classification */
-+static void stream_rule_set_group(struct stream_rule *rule, enum control_type type, struct group *group) {
-+    pa_assert(rule);
--static bool match_predicate(struct literal *l, pas_stream *d) {
-+    switch (type) {
-+        case CONTROL_TYPE_VOLUME:
-+            if (group == rule->group_for_volume)
-+                return;
--    if (l->stream_direction != match_direction_unknown) {
--        /* check the stream direction; _sink inputs_ are always _outputs_ */
-+            if (rule->group_for_volume)
-+                group_remove_stream_rule(rule->group_for_volume, CONTROL_TYPE_VOLUME, rule);
--        if ((d->direction == PA_DIRECTION_OUTPUT && l->stream_direction == match_direction_output) ||
--            ((d->direction == PA_DIRECTION_INPUT && l->stream_direction == match_direction_input))) {
--            return true;
--        }
-+            rule->group_for_volume = group;
-+
-+            if (group)
-+                group_add_stream_rule(group, CONTROL_TYPE_VOLUME, rule);
-+            break;
-+
-+        case CONTROL_TYPE_MUTE:
-+            if (group == rule->group_for_mute)
-+                return;
-+
-+            if (rule->group_for_mute)
-+                group_remove_stream_rule(rule->group_for_mute, CONTROL_TYPE_MUTE, rule);
-+
-+            rule->group_for_mute = group;
-+
-+            if (group)
-+                group_add_stream_rule(group, CONTROL_TYPE_MUTE, rule);
-+            break;
-     }
--    else if (l->property_name && l->property_value) {
--        /* check the property from the property list */
-+}
--        if (pa_proplist_contains(d->proplist, l->property_name)) {
--            const char *prop = pa_proplist_gets(d->proplist, l->property_name);
-+static void stream_rule_set_group_name(struct stream_rule *rule, enum control_type type, const char *name) {
-+    struct group *group = NULL;
--            if (prop && strcmp(prop, l->property_value) == 0) {
--                return true;
--            }
--        }
-+    pa_assert(rule);
-+
-+    switch (type) {
-+        case CONTROL_TYPE_VOLUME:
-+            pa_xfree(rule->audio_group_name_for_volume);
-+            rule->audio_group_name_for_volume = pa_xstrdup(name);
-+            break;
-+
-+        case CONTROL_TYPE_MUTE:
-+            pa_xfree(rule->audio_group_name_for_mute);
-+            rule->audio_group_name_for_mute = pa_xstrdup(name);
-+            break;
-     }
--    /* no match */
--    return false;
--}
-+    if (name)
-+        group = pa_hashmap_get(rule->userdata->groups, name);
--static bool match_rule(struct expression *e, pas_stream *d) {
-+    stream_rule_set_group(rule, type, group);
-+}
-+static bool stream_rule_match(struct stream_rule *rule, pas_stream *stream) {
-     struct conjunction *c;
--    PA_LLIST_FOREACH(c, e->conjunctions) {
-+    PA_LLIST_FOREACH(c, rule->match_expression->conjunctions) {
-         struct literal *l;
-         bool and_success = true;
-         PA_LLIST_FOREACH(l, c->literals) {
--            if (!match_predicate(l, d)) {
-+            if (!literal_match(l, stream)) {
-                 /* at least one fail for conjunction */
-                 and_success = false;
-                 break;
-@@ -421,56 +1012,246 @@ static bool match_rule(struct expression *e, pas_stream *d) {
-     return false;
- }
--static void classify_stream(struct userdata *u, pas_stream *new_data, bool mute) {
--    /* do the classification here */
-+/* stream classification */
--    struct stream *stream = NULL;
--    unsigned idx;
-+static bool literal_match(struct literal *literal, pas_stream *stream) {
-+
-+    if (literal->stream_direction != match_direction_unknown) {
-+        /* check the stream direction; _sink inputs_ are always _outputs_ */
--    /* go through the stream match definitions in given order */
-+        if ((stream->direction == PA_DIRECTION_OUTPUT && literal->stream_direction == match_direction_output) ||
-+            (stream->direction == PA_DIRECTION_INPUT && literal->stream_direction == match_direction_input)) {
-+            return literal->negation ? false : true;
-+        }
-+    }
-+    else if (literal->property_name && literal->property_value) {
-+        /* check the property from the property list */
--    PA_DYNARRAY_FOREACH(stream, u->streams, idx) {
--        if (stream->rule && match_rule(stream->rule, new_data)) {
--            pa_log_info("stream %s (%s) match with rule %s:", new_data->name, new_data->description, stream->id);
--            print_expression(stream->rule);
-+        if (pa_proplist_contains(stream->proplist, literal->property_name)) {
-+            const char *prop = pa_proplist_gets(stream->proplist, literal->property_name);
--            if (mute) {
--                if (new_data->use_default_mute_control && stream->audio_group_for_mute)
--                    pas_stream_bind_mute_control(new_data, stream->mute_control_target_info);
--            } else {
--                if (new_data->use_default_volume_control && stream->audio_group_for_volume)
--                    pas_stream_bind_volume_control(new_data, stream->volume_control_target_info);
--            }
-+            if (prop && strcmp(prop, literal->property_value) == 0)
-+                return literal->negation ? false : true;
-+        }
-+    }
-+
-+    /* no match */
-+    return literal->negation ? true : false;
-+}
-+
-+static pa_hook_result_t stream_put_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pas_stream *stream = call_data;
-+    struct stream_rule *rule;
-+    unsigned idx;
--            return;
-+    pa_assert(u);
-+    pa_assert(stream);
-+
-+    PA_DYNARRAY_FOREACH(rule, u->stream_rules_list, idx) {
-+        if (stream_rule_match(rule, stream)) {
-+            pa_hashmap_put(u->rules_by_stream, stream, rule);
-+            break;
-         }
-     }
--    /* no matches, don't touch the volumes */
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t stream_unlink_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pas_stream *stream = call_data;
-+
-+    pa_assert(u);
-+    pa_assert(stream);
-+
-+    pa_hashmap_remove(u->rules_by_stream, stream);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t volume_control_implementation_initialized_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_volume_control *volume_control = call_data;
-+    struct control *control;
-+
-+    pa_assert(u);
-+    pa_assert(volume_control);
-+
-+    if (volume_control->purpose != PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME)
-+        return PA_HOOK_OK;
-+
-+    control = control_new_for_stream(u, CONTROL_TYPE_VOLUME, volume_control->owner_stream);
-+    control_put(control);
-+    pa_assert_se(pa_hashmap_put(u->stream_volume_controls, volume_control->owner_stream, control) >= 0);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t mute_control_implementation_initialized_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_mute_control *mute_control = call_data;
-+    struct control *control;
-+
-+    pa_assert(u);
-+    pa_assert(mute_control);
-+
-+    if (mute_control->purpose != PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE)
-+        return PA_HOOK_OK;
-+
-+    control = control_new_for_stream(u, CONTROL_TYPE_MUTE, mute_control->owner_stream);
-+    control_put(control);
-+    pa_assert_se(pa_hashmap_put(u->stream_mute_controls, mute_control->owner_stream, control) >= 0);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t volume_control_set_initial_volume_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_volume_control *volume_control = call_data;
-+    struct stream_rule *rule;
-+    struct control *control;
-+
-+    pa_assert(u);
-+    pa_assert(volume_control);
-+
-+    if (volume_control->purpose != PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME)
-+        return PA_HOOK_OK;
-+
-+    rule = pa_hashmap_get(u->rules_by_stream, volume_control->owner_stream);
-+    if (!rule)
-+        return PA_HOOK_OK;
-+
-+    if (!rule->group_for_volume)
-+        return PA_HOOK_OK;
-+
-+    if (!rule->group_for_volume->volume_control)
-+        return PA_HOOK_OK;
-+
-+    control = pa_hashmap_get(u->stream_volume_controls, volume_control->owner_stream);
-+    pa_assert(control);
-+    pa_assert(control->volume_control == volume_control);
-+
-+    /* This will set the volume for volume_control. */
-+    control_set_master(control, rule->group_for_volume->volume_control);
-+
-+    return PA_HOOK_STOP;
-+}
-+
-+static pa_hook_result_t mute_control_set_initial_mute_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_mute_control *mute_control = call_data;
-+    struct stream_rule *rule;
-+    struct control *control;
-+
-+    pa_assert(u);
-+    pa_assert(mute_control);
-+
-+    if (mute_control->purpose != PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE)
-+        return PA_HOOK_OK;
-+
-+    rule = pa_hashmap_get(u->rules_by_stream, mute_control->owner_stream);
-+    if (!rule)
-+        return PA_HOOK_OK;
-+
-+    if (!rule->group_for_mute)
-+        return PA_HOOK_OK;
-+
-+    if (!rule->group_for_mute->mute_control)
-+        return PA_HOOK_OK;
-+
-+    control = pa_hashmap_get(u->stream_mute_controls, mute_control->owner_stream);
-+    pa_assert(control);
-+    pa_assert(control->mute_control == mute_control);
-+
-+    /* This will set the mute for mute_control. */
-+    control_set_master(control, rule->group_for_mute->mute_control);
-+
-+    return PA_HOOK_STOP;
-+}
-+
-+static pa_hook_result_t volume_control_volume_changed_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_volume_control *volume_control = call_data;
-+    struct control *control;
-+
-+    pa_assert(u);
-+    pa_assert(volume_control);
-+
-+    if (volume_control->purpose != PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME)
-+        return PA_HOOK_OK;
-+
-+    control = pa_hashmap_get(u->stream_volume_controls, volume_control->owner_stream);
-+    if (!control)
-+        return PA_HOOK_OK;
-+
-+    if (!control->master)
-+        return PA_HOOK_OK;
-+
-+    pa_volume_control_set_volume(control->master->volume_control, &volume_control->volume, true, true);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t mute_control_mute_changed_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_mute_control *mute_control = call_data;
-+    struct control *control;
-+
-+    pa_assert(u);
-+    pa_assert(mute_control);
-+
-+    if (mute_control->purpose != PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE)
-+        return PA_HOOK_OK;
-+
-+    control = pa_hashmap_get(u->stream_mute_controls, mute_control->owner_stream);
-+    if (!control)
-+        return PA_HOOK_OK;
-+
-+    if (!control->master)
-+        return PA_HOOK_OK;
-+
-+    pa_mute_control_set_mute(control->master->mute_control, mute_control->mute);
-+
-+    return PA_HOOK_OK;
- }
--static pa_hook_result_t set_volume_control_cb(
--        void *hook_data,
--        pas_stream *new_data,
--        struct userdata *u) {
-+static pa_hook_result_t volume_control_unlink_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_volume_control *volume_control = call_data;
-+    struct control *control;
--    pa_assert(new_data);
-     pa_assert(u);
-+    pa_assert(volume_control);
-+
-+    if (volume_control->purpose != PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME)
-+        return PA_HOOK_OK;
--    classify_stream(u, new_data, false);
-+    control = pa_hashmap_remove(u->stream_volume_controls, volume_control->owner_stream);
-+    if (!control)
-+        return PA_HOOK_OK;
-+
-+    control_free(control);
-     return PA_HOOK_OK;
- }
--static pa_hook_result_t set_mute_control_cb(
--        void *hook_data,
--        pas_stream *new_data,
--        struct userdata *u) {
-+static pa_hook_result_t mute_control_unlink_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_mute_control *mute_control = call_data;
-+    struct control *control;
--    pa_assert(new_data);
-     pa_assert(u);
-+    pa_assert(mute_control);
-+
-+    if (mute_control->purpose != PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE)
-+        return PA_HOOK_OK;
--    classify_stream(u, new_data, true);
-+    control = pa_hashmap_remove(u->stream_mute_controls, mute_control->owner_stream);
-+    if (!control)
-+        return PA_HOOK_OK;
-+
-+    control_free(control);
-     return PA_HOOK_OK;
- }
-@@ -520,6 +1301,7 @@ static pa_hook_result_t set_mute_control_cb(
-     (property application.process.binary=paplay OR (direction input OR direction output))
- */
-+#if 0
- static void print_literal(struct literal *l) {
-     if (l->stream_direction != match_direction_unknown) {
-         pa_log_info("       %sstream direction %s",
-@@ -549,6 +1331,7 @@ static void print_expression(struct expression *e) {
-         print_conjunction(c);
-     }
- }
-+#endif
- static void delete_literal(struct literal *l) {
-@@ -573,14 +1356,23 @@ static void delete_conjunction(struct conjunction *c) {
-     pa_xfree(c);
- }
--static void delete_expression(struct expression *e) {
-+static struct expression *expression_new(void) {
-+    struct expression *expression;
-+
-+    expression = pa_xnew0(struct expression, 1);
-+
-+    return expression;
-+}
-+
-+static void expression_free(struct expression *expression) {
-     struct conjunction *c;
--    PA_LLIST_FOREACH(c, e->conjunctions) {
-+    pa_assert(expression);
-+
-+    PA_LLIST_FOREACH(c, expression->conjunctions)
-         delete_conjunction(c);
--    }
--    pa_xfree(e);
-+    pa_xfree(expression);
- }
- enum logic_operator {
-@@ -917,26 +1709,21 @@ static bool gather_expression(struct expression *e, struct expression_token *et)
-     return true;
- }
--static struct expression *parse_rule(const char *rule_string) {
--    char *k, *l;
-+static int expression_from_string(const char *str, struct expression **_r) {
-+    const char *k;
-+    char *l;
-     struct expression *e = NULL;
--    int len;
-     char *buf = NULL;
-     struct expression_token *et = NULL;
--    if (!rule_string)
--        goto error;
--
--    len = strlen(rule_string);
--
--    buf = (char *) pa_xmalloc0(len);
-+    pa_assert(str);
-+    pa_assert(_r);
--    if (!buf)
--        goto error;
-+    buf = pa_xmalloc0(strlen(str) + 1);
-     /* remove whitespace */
--    k = (char *) rule_string;
-+    k = str;
-     l = buf;
-     while (*k) {
-@@ -958,9 +1745,6 @@ static struct expression *parse_rule(const char *rule_string) {
-     e = pa_xnew0(struct expression, 1);
--    if (!e)
--        goto error;
--
-     PA_LLIST_HEAD_INIT(struct conjunction, e->conjunctions);
-     /* gather expressions to actual match format */
-@@ -978,30 +1762,15 @@ static struct expression *parse_rule(const char *rule_string) {
-     delete_expression_token(et);
-     pa_xfree(buf);
--    return e;
-+    *_r = e;
-+    return 0;
- error:
-     delete_expression_token(et);
-     pa_xfree(buf);
--    pa_xfree(e);
--    return NULL;
--}
--
--static int parse_audio_groups(pa_config_parser_state *state) {
--    struct userdata *u;
--    char *name;
--    const char *split_state = NULL;
--
--    pa_assert(state);
--
--    u = state->userdata;
--
--    pa_hashmap_remove_all(u->audio_group_names);
-+    expression_free(e);
--    while ((name = pa_split_spaces(state->rvalue, &split_state)))
--        pa_hashmap_put(u->audio_group_names, name, name);
--
--    return 0;
-+    return -PA_ERR_INVALID;
- }
- static int parse_streams(pa_config_parser_state *state) {
-@@ -1013,15 +1782,13 @@ static int parse_streams(pa_config_parser_state *state) {
-     u = state->userdata;
--    pa_dynarray_remove_all(u->stream_names);
--
-     while ((name = pa_split_spaces(state->rvalue, &split_state))) {
-         const char *name2;
-         unsigned idx;
-         bool duplicate = false;
--        /* Avoid adding duplicates in u->stream_names. */
--        PA_DYNARRAY_FOREACH(name2, u->stream_names, idx) {
-+        /* Avoid adding duplicates in u->stream_rule_names. */
-+        PA_DYNARRAY_FOREACH(name2, u->stream_rule_names, idx) {
-             if (pa_streq(name, name2)) {
-                 duplicate = true;
-                 break;
-@@ -1033,230 +1800,221 @@ static int parse_streams(pa_config_parser_state *state) {
-             continue;
-         }
--        pa_dynarray_append(u->stream_names, name);
-+        pa_dynarray_append(u->stream_rule_names, name);
-     }
-     return 0;
- }
--static int parse_common(pa_config_parser_state *state) {
--#define AUDIOGROUP_START "AudioGroup "
--#define STREAM_START "Stream "
--#define BIND_KEYWORD "bind:"
--#define NONE_KEYWORD "none"
--
--    char *section;
--    struct userdata *u = (struct userdata *) state->userdata;
--    int r;
--    pa_binding_target_info *target_info;
--
-+static int parse_group_control(pa_config_parser_state *state, struct group *group, enum control_type type) {
-     pa_assert(state);
-+    pa_assert(group);
--    section = state->section;
--    if (!section)
--        goto error;
-+    if (pa_streq(state->rvalue, NONE_KEYWORD))
-+        group_disable_control(group, type);
-+
-+    else if (pa_startswith(state->rvalue, CREATE_PREFIX))
-+        group_set_own_control_name(group, type, state->rvalue + strlen(CREATE_PREFIX));
--    if (strncmp(section, AUDIOGROUP_START, strlen(AUDIOGROUP_START)) == 0) {
--        char *ag_name = section + strlen(AUDIOGROUP_START);
--        struct audio_group *ag = (struct audio_group *) pa_hashmap_get(u->unused_audio_groups, ag_name);
-+    else if (pa_startswith(state->rvalue, BIND_PREFIX)) {
-+        if (pa_startswith(state->rvalue, BIND_AUDIO_GROUP_PREFIX)) {
-+            int r;
--        if (!ag) {
--            /* first item for this audio group section, so create the struct */
--            ag = audio_group_new(u, ag_name);
--            pa_hashmap_put(u->unused_audio_groups, ag->id, ag);
-+            r = group_set_master_name(group, type, state->rvalue + strlen(BIND_AUDIO_GROUP_PREFIX));
-+            if (r < 0) {
-+                pa_log("[%s:%u] Failed to set binding target \"%s\".", state->filename, state->lineno, state->rvalue + strlen(BIND_PREFIX));
-+                return r;
-+            }
-+        } else {
-+            pa_log("[%s:%u] Failed to parse binding target \"%s\".", state->filename, state->lineno, state->rvalue + strlen(BIND_PREFIX));
-+            return -PA_ERR_INVALID;
-         }
-+    } else {
-+        pa_log("[%s:%u] Failed to parse value \"%s\".", state->filename, state->lineno, state->rvalue);
-+        return -PA_ERR_INVALID;
-+    }
--        if (strcmp(state->lvalue, "description") == 0)
--            audio_group_set_description(ag, state->rvalue);
-+    return 0;
-+}
-+
-+static int parse_common(pa_config_parser_state *state) {
-+    char *section;
-+    struct userdata *u = state->userdata;
-+    const char *name;
-+    int r;
--        else if (strcmp(state->lvalue, "volume-control") == 0) {
--            if (pa_streq(state->rvalue, "create"))
--                audio_group_set_volume_control_action(ag, CONTROL_ACTION_CREATE, NULL);
-+    pa_assert(state);
--            else if (pa_streq(state->rvalue, NONE_KEYWORD))
--                audio_group_set_volume_control_action(ag, CONTROL_ACTION_NONE, NULL);
-+    section = state->section;
-+    if (!section) {
-+        pa_log("[%s:%u] Lvalue \"%s\" not expected in the General section.", state->filename, state->lineno, state->lvalue);
-+        return -PA_ERR_INVALID;
-+    }
--            else if (pa_startswith(state->rvalue, BIND_KEYWORD)) {
--                r = pa_binding_target_info_new_from_string(state->rvalue, "volume_control", &target_info);
--                if (r < 0) {
--                    pa_log("[%s:%u] Failed to parse binding target \"%s\".", state->filename, state->lineno, state->rvalue);
--                    goto error;
--                }
-+    if (pa_startswith(section, AUDIOGROUP_START)) {
-+        struct group *group;
--                audio_group_set_volume_control_action(ag, CONTROL_ACTION_BIND, target_info);
--                pa_binding_target_info_free(target_info);
-+        name = section + strlen(AUDIOGROUP_START);
--            } else {
--                pa_log("[%s:%u] Failed to parse value \"%s\".", state->filename, state->lineno, state->rvalue);
--                goto error;
-+        group = pa_hashmap_get(u->groups, name);
-+        if (!group) {
-+            r = group_new(u, name, &group);
-+            if (r < 0) {
-+                pa_log("[%s:%u] Failed to create an audio group with name \"%s\".", state->filename, state->lineno, name);
-+                return r;
-             }
-+
-+            pa_hashmap_put(u->groups, (void *) group->audio_group->name, group);
-         }
--        else if (strcmp(state->lvalue, "mute-control") == 0) {
--            if (pa_streq(state->rvalue, "create"))
--                audio_group_set_mute_control_action(ag, CONTROL_ACTION_CREATE, NULL);
--
--            else if (pa_streq(state->rvalue, NONE_KEYWORD))
--                audio_group_set_mute_control_action(ag, CONTROL_ACTION_NONE, NULL);
--
--            else if (pa_startswith(state->rvalue, BIND_KEYWORD)) {
--                r = pa_binding_target_info_new_from_string(state->rvalue, "mute_control", &target_info);
--                if (r < 0) {
--                    pa_log("[%s:%u] Failed to parse binding target \"%s\".", state->filename, state->lineno, state->rvalue);
--                    goto error;
--                }
--                audio_group_set_mute_control_action(ag, CONTROL_ACTION_BIND, target_info);
--                pa_binding_target_info_free(target_info);
-+        if (pa_streq(state->lvalue, "description"))
-+            pa_audio_group_set_description(group->audio_group, state->rvalue);
--            } else {
--                pa_log("[%s:%u] Failed to parse value \"%s\".", state->filename, state->lineno, state->rvalue);
--                goto error;
--            }
-+        else if (pa_streq(state->lvalue, "volume-control"))
-+            return parse_group_control(state, group, CONTROL_TYPE_VOLUME);
-+
-+        else if (pa_streq(state->lvalue, "mute-control"))
-+            return parse_group_control(state, group, CONTROL_TYPE_MUTE);
-+
-+        else {
-+            pa_log("[%s:%u] Lvalue \"%s\" not expected in the AudioGroup section.", state->filename, state->lineno, state->lvalue);
-+            return -PA_ERR_INVALID;
-         }
-     }
--    else if (strncmp(section, STREAM_START, strlen(STREAM_START)) == 0) {
--        char *stream_name = section + strlen(STREAM_START);
-+    else if (pa_startswith(section, STREAM_RULE_START)) {
-+        struct stream_rule *rule;
--        struct stream *stream = (struct stream *) pa_hashmap_get(u->unused_streams, stream_name);
-+        name = section + strlen(STREAM_RULE_START);
--        if (!stream) {
--            /* first item for this stream section, so create the struct */
--            stream = stream_new(u, stream_name);
--            pa_hashmap_put(u->unused_streams, stream->id, stream);
-+        rule = pa_hashmap_get(u->stream_rules, name);
-+        if (!rule) {
-+            rule = stream_rule_new(u, name);
-+            pa_hashmap_put(u->stream_rules, rule->name, rule);
-         }
-         if (pa_streq(state->lvalue, "audio-group-for-volume"))
--            stream_set_audio_group_name_for_volume(stream, *state->rvalue ? state->rvalue : NULL);
-+            stream_rule_set_group_name(rule, CONTROL_TYPE_VOLUME, state->rvalue);
-         else if (pa_streq(state->lvalue, "audio-group-for-mute"))
--            stream_set_audio_group_name_for_mute(stream, *state->rvalue ? state->rvalue : NULL);
-+            stream_rule_set_group_name(rule, CONTROL_TYPE_MUTE, state->rvalue);
--        else if (strcmp(state->lvalue, "match") == 0) {
--            if (!state->rvalue)
--                goto error;
-+        else if (pa_streq(state->lvalue, "match")) {
-+            struct expression *expression;
--            stream->rule = parse_rule(state->rvalue);
--
--            if (!stream->rule) {
--                goto error;
-+            r = expression_from_string(state->rvalue, &expression);
-+            if (r < 0) {
-+                pa_log("[%s:%u] Failed to parse value \"%s\".", state->filename, state->lineno, state->rvalue);
-+                return r;
-             }
-+
-+            stream_rule_set_match_expression(rule, expression);
-         }
-     }
-     return 0;
--
--error:
--
--    pa_log_error("failed parsing audio group definition file");
--    return -1;
--
--#undef NONE_KEYWORD
--#undef AUDIO_GROUP_KEYWORD
--#undef BIND_KEYWORD
--#undef STREAM_START
--#undef AUDIOGROUP_START
- }
--static void finalize_config(struct userdata *u) {
--    const char *group_name;
-+int pa__init(pa_module *module) {
-+    pa_modargs *ma = NULL;
-+    struct userdata *u;
-+    FILE *f;
-+    char *fn = NULL;
-+    struct group *group;
-     void *state;
--    struct audio_group *group;
--    const char *stream_name;
-+    const char *name;
-     unsigned idx;
--    struct stream *stream;
--    pa_assert(u);
--
--    PA_HASHMAP_FOREACH(group_name, u->audio_group_names, state) {
--        int r;
-+    pa_assert(module);
--        group = pa_hashmap_remove(u->unused_audio_groups, group_name);
--        if (!group)
--            group = audio_group_new(u, group_name);
--
--        r = audio_group_put(group);
--        if (r < 0) {
--            pa_log("Failed to create audio group %s.", group_name);
--            audio_group_free(group);
--            continue;
--        }
--
--        pa_assert_se(pa_hashmap_put(u->audio_groups, group->id, group) >= 0);
-+    if (!(ma = pa_modargs_new(module->argument, valid_modargs))) {
-+        pa_log("Failed to parse module arguments");
-+        goto fail;
-     }
--    PA_HASHMAP_FOREACH(group, u->unused_audio_groups, state)
--        pa_log_debug("Audio group %s is not used.", group->id);
--
--    pa_hashmap_free(u->unused_audio_groups);
--    u->unused_audio_groups = NULL;
--
--    pa_hashmap_free(u->audio_group_names);
--    u->audio_group_names = NULL;
--
--    PA_DYNARRAY_FOREACH(stream_name, u->stream_names, idx) {
--        stream = pa_hashmap_remove(u->unused_streams, stream_name);
--        if (!stream) {
--            pa_log("Reference to undefined stream %s, ignoring.", stream_name);
--            continue;
--        }
-+    u = module->userdata = pa_xnew0(struct userdata, 1);
-+    u->volume_api = pa_volume_api_get(module->core);
-+    u->groups = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
-+                                    (pa_free_cb_t) group_free);
-+    u->stream_rules = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
-+                                          (pa_free_cb_t) stream_rule_free);
-+    u->stream_rules_list = pa_dynarray_new(NULL);
-+    u->rules_by_stream = pa_hashmap_new(NULL, NULL);
-+    u->stream_volume_controls = pa_hashmap_new_full(NULL, NULL, NULL, (pa_free_cb_t) control_free);
-+    u->stream_mute_controls = pa_hashmap_new_full(NULL, NULL, NULL, (pa_free_cb_t) control_free);
-+    u->stream_put_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_PUT], PA_HOOK_NORMAL, stream_put_cb,
-+                                         u);
-+    u->stream_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_UNLINK], PA_HOOK_NORMAL,
-+                                            stream_unlink_cb, u);
-+    u->volume_control_implementation_initialized_slot =
-+            pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_IMPLEMENTATION_INITIALIZED],
-+                            PA_HOOK_NORMAL, volume_control_implementation_initialized_cb, u);
-+    u->mute_control_implementation_initialized_slot =
-+            pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_IMPLEMENTATION_INITIALIZED],
-+                            PA_HOOK_NORMAL, mute_control_implementation_initialized_cb, u);
-+    u->volume_control_set_initial_volume_slot =
-+            pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_SET_INITIAL_VOLUME], PA_HOOK_NORMAL,
-+                            volume_control_set_initial_volume_cb, u);
-+    u->mute_control_set_initial_mute_slot =
-+            pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_SET_INITIAL_MUTE], PA_HOOK_NORMAL,
-+                            mute_control_set_initial_mute_cb, u);
-+    u->volume_control_volume_changed_slot =
-+            pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_VOLUME_CHANGED], PA_HOOK_NORMAL,
-+                            volume_control_volume_changed_cb, u);
-+    u->mute_control_mute_changed_slot =
-+            pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_MUTE_CHANGED], PA_HOOK_NORMAL,
-+                            mute_control_mute_changed_cb, u);
-+    u->volume_control_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK],
-+                                                    PA_HOOK_NORMAL, volume_control_unlink_cb, u);
-+    u->mute_control_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK],
-+                                                  PA_HOOK_NORMAL, mute_control_unlink_cb, u);
-+    u->stream_rule_names = pa_dynarray_new(pa_xfree);
-+
-+    f = pa_open_config_file(PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "audio-groups.conf", "audio-groups.conf", NULL, &fn);
-+    if (f) {
-+        pa_config_item config_items[] = {
-+            { "stream-rules", parse_streams, NULL, "General" },
-+            { NULL, parse_common, NULL, NULL },
-+            { NULL, NULL, NULL, NULL },
-+        };
--        stream_put(stream);
--        pa_dynarray_append(u->streams, stream);
-+        pa_config_parse(fn, f, config_items, NULL, u);
-+        pa_xfree(fn);
-+        fn = NULL;
-+        fclose(f);
-+        f = NULL;
-     }
--    PA_HASHMAP_FOREACH(stream, u->unused_streams, state)
--        pa_log_debug("Stream %s is not used.", stream->id);
--
--    pa_hashmap_free(u->unused_streams);
--    u->unused_streams = NULL;
--
--    pa_dynarray_free(u->stream_names);
--    u->stream_names = NULL;
--}
-+    PA_HASHMAP_FOREACH(group, u->groups, state)
-+        group_put(group);
--static bool parse_configuration(struct userdata *u, const char *filename) {
--    FILE *f;
--    char *fn = NULL;
-+    PA_DYNARRAY_FOREACH(name, u->stream_rule_names, idx) {
-+        struct stream_rule *rule;
--    pa_config_item table[] = {
--        { "audio-groups", parse_audio_groups, NULL, "General" },
--        { "streams", parse_streams, NULL, "General" },
--        { NULL, parse_common, NULL, NULL },
--        { NULL, NULL, NULL, NULL },
--    };
-+        rule = pa_hashmap_get(u->stream_rules, name);
-+        if (rule)
-+            pa_dynarray_append(u->stream_rules_list, rule);
-+        else
-+            pa_log("Non-existent stream rule \"%s\" referenced, ignoring.", name);
-+    }
--    u->audio_group_names = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
--    u->unused_audio_groups = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
--                                                 (pa_free_cb_t) audio_group_free);
--    u->stream_names = pa_dynarray_new(pa_xfree);
--    u->unused_streams = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
--                                            (pa_free_cb_t) stream_free);
-+    pa_dynarray_free(u->stream_rule_names);
-+    u->stream_rule_names = NULL;
--    if (pa_is_path_absolute(filename))
--        f = pa_open_config_file(filename, NULL, NULL, &fn);
--    else {
--        char *sys_conf_file;
-+    pa_modargs_free(ma);
--        sys_conf_file = pa_sprintf_malloc(PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "%s", filename);
--        f = pa_open_config_file(sys_conf_file, filename, NULL, &fn);
--        pa_xfree(sys_conf_file);
--    }
-+    return 0;
--    if (f) {
--        pa_config_parse(fn, f, table, NULL, u);
--        pa_xfree(fn);
--        fn = NULL;
--        fclose(f);
--        f = NULL;
--    }
-+fail:
-+    pa__done(module);
--    finalize_config(u);
-+    if (ma)
-+        pa_modargs_free(ma);
--    return true;
-+    return -1;
- }
- void pa__done(pa_module *m) {
--    struct userdata* u;
-+    struct userdata *u;
-     pa_assert(m);
-@@ -1265,70 +2023,56 @@ void pa__done(pa_module *m) {
-     if (!u)
-         return;
--    if (u->new_stream_volume)
--        pa_hook_slot_free(u->new_stream_volume);
-+    if (u->mute_control_unlink_slot)
-+        pa_hook_slot_free(u->mute_control_unlink_slot);
--    if (u->new_stream_mute)
--        pa_hook_slot_free(u->new_stream_mute);
-+    if (u->volume_control_unlink_slot)
-+        pa_hook_slot_free(u->volume_control_unlink_slot);
--    if (u->streams)
--        pa_dynarray_free(u->streams);
-+    if (u->mute_control_mute_changed_slot)
-+        pa_hook_slot_free(u->mute_control_mute_changed_slot);
--    if (u->audio_groups)
--        pa_hashmap_free(u->audio_groups);
-+    if (u->volume_control_volume_changed_slot)
-+        pa_hook_slot_free(u->volume_control_volume_changed_slot);
--    if (u->api)
--        pa_volume_api_unref(u->api);
-+    if (u->mute_control_set_initial_mute_slot)
-+        pa_hook_slot_free(u->mute_control_set_initial_mute_slot);
--    pa_xfree(u);
--}
-+    if (u->volume_control_set_initial_volume_slot)
-+        pa_hook_slot_free(u->volume_control_set_initial_volume_slot);
--int pa__init(pa_module *m) {
--    pa_modargs *ma = NULL;
--    struct userdata *u;
--    const char *filename;
-+    if (u->mute_control_implementation_initialized_slot)
-+        pa_hook_slot_free(u->mute_control_implementation_initialized_slot);
--    pa_assert(m);
-+    if (u->volume_control_implementation_initialized_slot)
-+        pa_hook_slot_free(u->volume_control_implementation_initialized_slot);
--    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
--        pa_log("Failed to parse module arguments");
--        goto error;
--    }
-+    if (u->stream_unlink_slot)
-+        pa_hook_slot_free(u->stream_unlink_slot);
--    u = m->userdata = pa_xnew0(struct userdata, 1);
-+    if (u->stream_put_slot)
-+        pa_hook_slot_free(u->stream_put_slot);
--    if (!u)
--        goto error;
-+    if (u->stream_mute_controls)
-+        pa_hashmap_free(u->stream_mute_controls);
--    u->api = pa_volume_api_get(m->core);
-+    if (u->stream_volume_controls)
-+        pa_hashmap_free(u->stream_volume_controls);
--    if (!u->api)
--        goto error;
--
--    u->audio_groups = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
--                                          (pa_free_cb_t) audio_group_free);
--    u->streams = pa_dynarray_new((pa_free_cb_t) stream_free);
--
--    filename = pa_modargs_get_value(ma, "filename", AUDIO_GROUP_CONFIG);
--
--    if (!parse_configuration(u, filename))
--        goto error;
-+    if (u->rules_by_stream)
-+        pa_hashmap_free(u->rules_by_stream);
--    u->new_stream_volume = pa_hook_connect(&u->api->hooks[PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_VOLUME_CONTROL], PA_HOOK_EARLY, (pa_hook_cb_t) set_volume_control_cb, u);
--    u->new_stream_mute = pa_hook_connect(&u->api->hooks[PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_MUTE_CONTROL], PA_HOOK_EARLY, (pa_hook_cb_t) set_mute_control_cb, u);
-+    if (u->stream_rules_list)
-+        pa_dynarray_free(u->stream_rules_list);
--    if (!u->new_stream_volume || !u->new_stream_mute)
--        goto error;
-+    if (u->stream_rules)
-+        pa_hashmap_free(u->stream_rules);
--    pa_modargs_free(ma);
-+    if (u->groups)
-+        pa_hashmap_free(u->groups);
--    return 0;
-+    if (u->volume_api)
-+        pa_volume_api_unref(u->volume_api);
--error:
--    pa__done(m);
--
--    if (ma)
--        pa_modargs_free(ma);
--
--    return -1;
-+    pa_xfree(u);
- }
-diff --git a/src/modules/main-volume-policy/main-volume-context.c b/src/modules/main-volume-policy/main-volume-context.c
-index 7ac35c6..9b9f9fd 100644
---- a/src/modules/main-volume-policy/main-volume-context.c
-+++ b/src/modules/main-volume-policy/main-volume-context.c
-@@ -28,32 +28,33 @@
- #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;
-+#include <pulsecore/core-util.h>
-+
-+int pa_main_volume_context_new(pa_main_volume_policy *policy, const char *name, void *userdata, pa_main_volume_context **_r) {
-+    pa_main_volume_context *context;
-     int r;
-     pa_assert(policy);
-     pa_assert(name);
--    pa_assert(description);
--    pa_assert(context);
-+    pa_assert(_r);
--    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);
-+    context = pa_xnew0(struct pa_main_volume_context, 1);
-+    context->main_volume_policy = policy;
-+    context->index = pa_main_volume_policy_allocate_main_volume_context_index(policy);
--    r = pa_main_volume_policy_register_name(policy, name, true, &context_local->name);
-+    r = pa_main_volume_policy_register_name(policy, name, true, &context->name);
-     if (r < 0)
-         goto fail;
--    context_local->description = pa_xstrdup(description);
--
--    *context = context_local;
-+    context->description = pa_xstrdup(context->name);
-+    context->userdata = userdata;
-+    *_r = context;
-     return 0;
- fail:
--    pa_main_volume_context_free(context_local);
-+    if (context)
-+        pa_main_volume_context_free(context);
-     return r;
- }
-@@ -62,7 +63,6 @@ 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);
-@@ -93,40 +93,21 @@ void pa_main_volume_context_unlink(pa_main_volume_context *context) {
-     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;
--    }
-+        pa_main_volume_policy_remove_main_volume_context(context->main_volume_policy, context);
--    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;
--    }
-+    pa_hook_fire(&context->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK], context);
-     context->main_input_mute_control = NULL;
-     context->main_output_mute_control = NULL;
-     context->main_input_volume_control = NULL;
-     context->main_output_volume_control = NULL;
--
--    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)
-+    /* unlink() expects name to be set. */
-+    if (!context->unlinked && context->name)
-         pa_main_volume_context_unlink(context);
-     pa_xfree(context->description);
-@@ -137,13 +118,33 @@ void pa_main_volume_context_free(pa_main_volume_context *context) {
-     pa_xfree(context);
- }
--const char *pa_main_volume_context_get_name(pa_main_volume_context *context) {
-+void pa_main_volume_context_set_description(pa_main_volume_context *context, const char *description) {
-+    char *old_description;
-+
-     pa_assert(context);
-+    pa_assert(description);
-+
-+    old_description = context->description;
-+
-+    if (pa_streq(description, old_description))
-+        return;
--    return context->name;
-+    context->description = pa_xstrdup(description);
-+
-+    if (!context->linked || context->unlinked) {
-+        pa_xfree(old_description);
-+        return;
-+    }
-+
-+    pa_log_debug("Main volume context %s description changed from \"%s\" to \"%s\".", context->name, old_description,
-+                 description);
-+    pa_xfree(old_description);
-+
-+    pa_hook_fire(&context->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_DESCRIPTION_CHANGED],
-+                 context);
- }
--static void set_main_output_volume_control_internal(pa_main_volume_context *context, pa_volume_control *control) {
-+void pa_main_volume_context_set_main_output_volume_control(pa_main_volume_context *context, pa_volume_control *control) {
-     pa_volume_control *old_control;
-     pa_assert(context);
-@@ -158,7 +159,7 @@ static void set_main_output_volume_control_internal(pa_main_volume_context *cont
-     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,
-+    pa_log_debug("Main volume context %s main output volume control changed from %s to %s.", context->name,
-                  old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-     pa_hook_fire(&context->main_volume_policy->hooks
-@@ -166,24 +167,7 @@ static void set_main_output_volume_control_internal(pa_main_volume_context *cont
-                  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) {
-+void pa_main_volume_context_set_main_input_volume_control(pa_main_volume_context *context, pa_volume_control *control) {
-     pa_volume_control *old_control;
-     pa_assert(context);
-@@ -198,7 +182,7 @@ static void set_main_input_volume_control_internal(pa_main_volume_context *conte
-     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,
-+    pa_log_debug("Main volume context %s main input volume control changed from %s to %s.", context->name,
-                  old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-     pa_hook_fire(&context->main_volume_policy->hooks
-@@ -206,24 +190,7 @@ static void set_main_input_volume_control_internal(pa_main_volume_context *conte
-                  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) {
-+void pa_main_volume_context_set_main_output_mute_control(pa_main_volume_context *context, pa_mute_control *control) {
-     pa_mute_control *old_control;
-     pa_assert(context);
-@@ -238,7 +205,7 @@ static void set_main_output_mute_control_internal(pa_main_volume_context *contex
-     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,
-+    pa_log_debug("Main volume context %s main output mute control changed from %s to %s.", context->name,
-                  old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-     pa_hook_fire(&context->main_volume_policy->hooks
-@@ -246,24 +213,7 @@ static void set_main_output_mute_control_internal(pa_main_volume_context *contex
-                  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) {
-+void pa_main_volume_context_set_main_input_mute_control(pa_main_volume_context *context, pa_mute_control *control) {
-     pa_mute_control *old_control;
-     pa_assert(context);
-@@ -278,48 +228,10 @@ static void set_main_input_mute_control_internal(pa_main_volume_context *context
-     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,
-+    pa_log_debug("Main volume context %s main input mute control changed from %s to %s.", context->name,
-                  old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-     pa_hook_fire(&context->main_volume_policy->hooks
-                      [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_MUTE_CONTROL_CHANGED],
-                  context);
- }
--
--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
-index 4a0a6f7..3770168 100644
---- a/src/modules/main-volume-policy/main-volume-context.h
-+++ b/src/modules/main-volume-policy/main-volume-context.h
-@@ -24,16 +24,8 @@
- #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;
-@@ -44,32 +36,21 @@ struct pa_main_volume_context {
-     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;
-+
-+    void *userdata;
- };
--int pa_main_volume_context_new(pa_main_volume_policy *policy, const char *name, const char *description,
--                               pa_main_volume_context **context);
-+int pa_main_volume_context_new(pa_main_volume_policy *policy, const char *name, void *userdata, pa_main_volume_context **_r);
- void pa_main_volume_context_put(pa_main_volume_context *context);
- void pa_main_volume_context_unlink(pa_main_volume_context *context);
- void pa_main_volume_context_free(pa_main_volume_context *context);
--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);
-+void pa_main_volume_context_set_description(pa_main_volume_context *context, const char *description);
-+void pa_main_volume_context_set_main_output_volume_control(pa_main_volume_context *context, pa_volume_control *control);
-+void pa_main_volume_context_set_main_input_volume_control(pa_main_volume_context *context, pa_volume_control *control);
-+void pa_main_volume_context_set_main_output_mute_control(pa_main_volume_context *context, pa_mute_control *control);
-+void pa_main_volume_context_set_main_input_mute_control(pa_main_volume_context *context, pa_mute_control *control);
- #endif
-diff --git a/src/modules/main-volume-policy/main-volume-policy.c b/src/modules/main-volume-policy/main-volume-policy.c
-index b0b4ede..3c0fccf 100644
---- a/src/modules/main-volume-policy/main-volume-policy.c
-+++ b/src/modules/main-volume-policy/main-volume-policy.c
-@@ -28,6 +28,7 @@
- #include <modules/main-volume-policy/main-volume-context.h>
- #include <pulsecore/core-util.h>
-+#include <pulsecore/namereg.h>
- #include <pulsecore/shared.h>
- static pa_main_volume_policy *main_volume_policy_new(pa_core *core);
-@@ -70,6 +71,46 @@ void pa_main_volume_policy_unref(pa_main_volume_policy *policy) {
-     }
- }
-+static pa_hook_result_t volume_control_unlink_cb(void *hook_data, void *call_data, void *userdata) {
-+    pa_main_volume_policy *policy = userdata;
-+    pa_volume_control *control = call_data;
-+    pa_main_volume_context *context;
-+    void *state;
-+
-+    pa_assert(policy);
-+    pa_assert(control);
-+
-+    PA_HASHMAP_FOREACH(context, policy->main_volume_contexts, state) {
-+        if (context->main_output_volume_control == control)
-+            pa_main_volume_context_set_main_output_volume_control(context, NULL);
-+
-+        if (context->main_input_volume_control == control)
-+            pa_main_volume_context_set_main_input_volume_control(context, NULL);
-+    }
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t mute_control_unlink_cb(void *hook_data, void *call_data, void *userdata) {
-+    pa_main_volume_policy *policy = userdata;
-+    pa_mute_control *control = call_data;
-+    pa_main_volume_context *context;
-+    void *state;
-+
-+    pa_assert(policy);
-+    pa_assert(control);
-+
-+    PA_HASHMAP_FOREACH(context, policy->main_volume_contexts, state) {
-+        if (context->main_output_mute_control == control)
-+            pa_main_volume_context_set_main_output_mute_control(context, NULL);
-+
-+        if (context->main_input_mute_control == control)
-+            pa_main_volume_context_set_main_input_mute_control(context, NULL);
-+    }
-+
-+    return PA_HOOK_OK;
-+}
-+
- static pa_main_volume_policy *main_volume_policy_new(pa_core *core) {
-     pa_main_volume_policy *policy;
-     unsigned i;
-@@ -86,8 +127,10 @@ static pa_main_volume_policy *main_volume_policy_new(pa_core *core) {
-     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);
-+    policy->volume_control_unlink_slot = pa_hook_connect(&policy->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK],
-+                                                         PA_HOOK_NORMAL, volume_control_unlink_cb, policy);
-+    policy->mute_control_unlink_slot = pa_hook_connect(&policy->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK],
-+                                                       PA_HOOK_NORMAL, mute_control_unlink_cb, policy);
-     pa_log_debug("Created a pa_main_volume_policy object.");
-@@ -102,10 +145,11 @@ static void main_volume_policy_free(pa_main_volume_policy *policy) {
-     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);
--    }
-+    if (policy->mute_control_unlink_slot)
-+        pa_hook_slot_free(policy->mute_control_unlink_slot);
-+
-+    if (policy->volume_control_unlink_slot)
-+        pa_hook_slot_free(policy->volume_control_unlink_slot);
-     for (i = 0; i < PA_MAIN_VOLUME_POLICY_HOOK_MAX; i++)
-         pa_hook_done(&policy->hooks[i]);
-@@ -134,19 +178,24 @@ int pa_main_volume_policy_register_name(pa_main_volume_policy *policy, const cha
-     pa_assert(requested_name);
-     pa_assert(registered_name);
-+    if (!pa_namereg_is_valid_name(requested_name)) {
-+        pa_log("Invalid name: \"%s\"", requested_name);
-+        return -PA_ERR_INVALID;
-+    }
-+
-     n = pa_xstrdup(requested_name);
-     if (pa_hashmap_put(policy->names, n, n) < 0) {
-         unsigned i = 1;
--        pa_xfree(n);
--
-         if (fail_if_already_registered) {
-+            pa_xfree(n);
-             pa_log("Name %s already registered.", requested_name);
-             return -PA_ERR_EXIST;
-         }
-         do {
-+            pa_xfree(n);
-             i++;
-             n = pa_sprintf_malloc("%s.%u", requested_name, i);
-         } while (pa_hashmap_put(policy->names, n, n) < 0);
-diff --git a/src/modules/main-volume-policy/main-volume-policy.conf.example b/src/modules/main-volume-policy/main-volume-policy.conf.example
-index a4a35d3..3fcd267 100644
---- a/src/modules/main-volume-policy/main-volume-policy.conf.example
-+++ b/src/modules/main-volume-policy/main-volume-policy.conf.example
-@@ -3,7 +3,6 @@ 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
-diff --git a/src/modules/main-volume-policy/main-volume-policy.h b/src/modules/main-volume-policy/main-volume-policy.h
-index 5cd669e..d5f6e02 100644
---- a/src/modules/main-volume-policy/main-volume-policy.h
-+++ b/src/modules/main-volume-policy/main-volume-policy.h
-@@ -22,7 +22,6 @@
-   USA.
- ***/
--#include <modules/volume-api/binding.h>
- #include <modules/volume-api/volume-api.h>
- #include <pulsecore/core.h>
-@@ -35,6 +34,7 @@ typedef struct pa_main_volume_context pa_main_volume_context;
- enum {
-     PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_PUT,
-     PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK,
-+    PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_DESCRIPTION_CHANGED,
-     PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED,
-     PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_VOLUME_CONTROL_CHANGED,
-     PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_MUTE_CONTROL_CHANGED,
-@@ -53,7 +53,9 @@ struct pa_main_volume_policy {
-     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_hook_slot *volume_control_unlink_slot;
-+    pa_hook_slot *mute_control_unlink_slot;
- };
- pa_main_volume_policy *pa_main_volume_policy_get(pa_core *core);
-diff --git a/src/modules/main-volume-policy/module-main-volume-policy.c b/src/modules/main-volume-policy/module-main-volume-policy.c
-index 0a89aa7..1b7693e 100644
---- a/src/modules/main-volume-policy/module-main-volume-policy.c
-+++ b/src/modules/main-volume-policy/module-main-volume-policy.c
-@@ -27,7 +27,7 @@
- #include <modules/main-volume-policy/main-volume-context.h>
--#include <modules/volume-api/binding.h>
-+#include <modules/volume-api/audio-group.h>
- #include <modules/volume-api/volume-api.h>
- #include <pulse/direction.h>
-@@ -36,6 +36,9 @@
- #include <pulsecore/core-util.h>
- #include <pulsecore/i18n.h>
-+#define BIND_PREFIX "bind:"
-+#define BIND_AUDIO_GROUP_PREFIX BIND_PREFIX "AudioGroup:"
-+
- PA_MODULE_AUTHOR("Tanu Kaskinen");
- PA_MODULE_DESCRIPTION(_("Main volume and mute policy"));
- PA_MODULE_VERSION(PACKAGE_VERSION);
-@@ -52,6 +55,7 @@ enum model {
- };
- struct userdata {
-+    pa_volume_api *volume_api;
-     pa_main_volume_policy *main_volume_policy;
-     enum model output_volume_model;
-     enum model input_volume_model;
-@@ -60,26 +64,67 @@ struct userdata {
-     pa_hashmap *contexts; /* name -> struct context */
-     pa_hook_slot *active_main_volume_context_changed_slot;
-+    pa_hook_slot *main_volume_context_main_output_volume_control_changed_slot;
-+    pa_hook_slot *main_volume_context_main_input_volume_control_changed_slot;
-+    pa_hook_slot *main_volume_context_main_output_mute_control_changed_slot;
-+    pa_hook_slot *main_volume_context_main_input_mute_control_changed_slot;
-+    pa_hook_slot *audio_group_put_slot;
-+    pa_hook_slot *audio_group_unlink_slot;
-+    pa_hook_slot *audio_group_volume_control_changed_slot;
-+    pa_hook_slot *audio_group_mute_control_changed_slot;
-+};
--    /* 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 control_info {
-+    /* As appropriate for this control, points to one of
-+     *  - pa_main_volume_context.main_output_volume_control
-+     *  - pa_main_volume_context.main_input_volume_control
-+     *  - pa_main_volume_context.main_output_mute_control
-+     *  - pa_main_volume_context.main_input_mute_control */
-+    void **control;
-+
-+    /* As appropriate for this control, points to one of
-+     *  - userdata.output_volume_model
-+     *  - userdata.input_volume_model
-+     *  - userdata.output_mute_model
-+     *  - userdata.input_mute_model */
-+    enum model *model;
-+
-+    /* Name of the audio group to which the context volume or mute control is
-+     * bound. If the context control is not bound to anything, this is NULL. */
-+    char *binding_target_name;
-+
-+    /* Points to the audio group to which the context volume or mute control is
-+     * bound. If the context control is not bound to anything, or it's bound
-+     * but the target doesn't currently exist, this is NULL. */
-+    pa_audio_group *binding_target;
-+
-+    /* As appropriate for this control, points to one of
-+     *  - pa_main_volume_context_set_main_output_volume_control()
-+     *  - pa_main_volume_context_set_main_input_volume_control()
-+     *  - pa_main_volume_context_set_main_output_mute_control()
-+     *  - pa_main_volume_context_set_main_input_mute_control() */
-+    void (*set_control)(pa_main_volume_context *context, void *control);
-+
-+    /* As appropriate for this control, points to one of
-+     *  - pa_volume_api_set_main_output_volume_control()
-+     *  - pa_volume_api_set_main_input_volume_control()
-+     *  - pa_volume_api_set_main_output_mute_control()
-+     *  - pa_volume_api_set_main_input_mute_control() */
-+    void (*set_volume_api_control)(pa_volume_api *api, void *control);
- };
- struct context {
-     struct userdata *userdata;
--    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;
-+    struct control_info output_volume_info;
-+    struct control_info input_volume_info;
-+    struct control_info output_mute_info;
-+    struct control_info input_mute_info;
-     bool unlinked;
- };
--static void context_unlink(struct context *context);
-+static void context_free(struct context *context);
- static const char *model_to_string(enum model model) {
-     switch (model) {
-@@ -107,56 +152,57 @@ static int model_from_string(const char *str, enum model *model) {
-     return 0;
- }
--static struct context *context_new(struct userdata *u, const char *name) {
--    struct context *context;
-+static int context_new(struct userdata *u, const char *name, struct context **_r) {
-+    struct context *context = NULL;
-+    int r;
-     pa_assert(u);
-     pa_assert(name);
-+    pa_assert(_r);
-     context = pa_xnew0(struct context, 1);
-     context->userdata = u;
--    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);
-+    r = pa_main_volume_context_new(u->main_volume_policy, name, u, &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);
-+    context->output_volume_info.control = (void **) &context->main_volume_context->main_output_volume_control;
-+    context->input_volume_info.control = (void **) &context->main_volume_context->main_input_volume_control;
-+    context->output_mute_info.control = (void **) &context->main_volume_context->main_output_mute_control;
-+    context->input_mute_info.control = (void **) &context->main_volume_context->main_input_mute_control;
--    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);
-+    context->output_volume_info.model = &u->output_volume_model;
-+    context->input_volume_info.model = &u->input_volume_model;
-+    context->output_mute_info.model = &u->output_mute_model;
-+    context->input_mute_info.model = &u->input_mute_model;
--    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);
-+    context->output_volume_info.set_control = (void *) pa_main_volume_context_set_main_output_volume_control;
-+    context->input_volume_info.set_control = (void *) pa_main_volume_context_set_main_input_volume_control;
-+    context->output_mute_info.set_control = (void *) pa_main_volume_context_set_main_output_mute_control;
-+    context->input_mute_info.set_control = (void *) pa_main_volume_context_set_main_input_mute_control;
--    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);
-+    context->output_volume_info.set_volume_api_control = (void *) pa_volume_api_set_main_output_volume_control;
-+    context->input_volume_info.set_volume_api_control = (void *) pa_volume_api_set_main_input_volume_control;
-+    context->output_mute_info.set_volume_api_control = (void *) pa_volume_api_set_main_output_mute_control;
-+    context->input_mute_info.set_volume_api_control = (void *) pa_volume_api_set_main_input_mute_control;
-+    *_r = context;
-     return 0;
- fail:
--    context_unlink(context);
-+    if (context)
-+        context_free(context);
-     return r;
- }
-+static void context_put(struct context *context) {
-+    pa_assert(context);
-+
-+    pa_main_volume_context_put(context->main_volume_context);
-+}
-+
- static void context_unlink(struct context *context) {
-     pa_assert(context);
-@@ -165,10 +211,8 @@ static void context_unlink(struct context *context) {
-     context->unlinked = true;
--    if (context->main_volume_context) {
--        pa_main_volume_context_free(context->main_volume_context);
--        context->main_volume_context = NULL;
--    }
-+    if (context->main_volume_context)
-+        pa_main_volume_context_unlink(context->main_volume_context);
- }
- static void context_free(struct context *context) {
-@@ -177,132 +221,290 @@ static void context_free(struct context *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);
-+    if (context->main_volume_context)
-+        pa_main_volume_context_free(context->main_volume_context);
--    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) {
-+static struct control_info *context_get_control_info(struct context *context, enum control_type type,
-+                                                     pa_direction_t direction) {
-     pa_assert(context);
-     switch (type) {
-         case CONTROL_TYPE_VOLUME:
--            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;
-+            switch (direction) {
-+                case PA_DIRECTION_OUTPUT:
-+                    return &context->output_volume_info;
-+
-+                case PA_DIRECTION_INPUT:
-+                    return &context->input_volume_info;
-             }
-             break;
-         case CONTROL_TYPE_MUTE:
--            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;
-+            switch (direction) {
-+                case PA_DIRECTION_OUTPUT:
-+                    return &context->output_mute_info;
-+
-+                case PA_DIRECTION_INPUT:
-+                    return &context->input_mute_info;
-             }
-             break;
-     }
-+
-+    pa_assert_not_reached();
-+}
-+
-+static void context_set_binding_target(struct context *context, enum control_type type, pa_direction_t direction,
-+                                       pa_audio_group *group) {
-+    struct control_info *info;
-+    void *control = NULL;
-+
-+    pa_assert(context);
-+
-+    info = context_get_control_info(context, type, direction);
-+    info->binding_target = group;
-+
-+    if (group) {
-+        switch (type) {
-+            case CONTROL_TYPE_VOLUME:
-+                control = group->volume_control;
-+                break;
-+
-+            case CONTROL_TYPE_MUTE:
-+                control = group->mute_control;
-+                break;
-+        }
-+    }
-+
-+    info->set_control(context->main_volume_context, control);
-+}
-+
-+static void context_set_binding_target_name(struct context *context, enum control_type type, pa_direction_t direction,
-+                                            const char *name) {
-+    struct control_info *info;
-+    pa_audio_group *group = NULL;
-+
-+    pa_assert(context);
-+
-+    info = context_get_control_info(context, type, direction);
-+
-+    if (pa_safe_streq(name, info->binding_target_name))
-+        return;
-+
-+    pa_xfree(info->binding_target_name);
-+    info->binding_target_name = pa_xstrdup(name);
-+
-+    if (name)
-+        group = pa_hashmap_get(context->userdata->volume_api->audio_groups, name);
-+
-+    context_set_binding_target(context, type, direction, group);
- }
- static pa_hook_result_t active_main_volume_context_changed_cb(void *hook_data, void *call_data, void *userdata) {
-     struct userdata *u = userdata;
-     pa_main_volume_context *context;
--    pa_volume_api *api;
--    pa_binding_target_info *info;
-     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);
--            pa_binding_target_info_free(info);
--        } else
--            pa_volume_api_set_main_output_volume_control(api, NULL);
-+        if (context)
-+            pa_volume_api_set_main_output_volume_control(u->volume_api, context->main_output_volume_control);
-+        else
-+            pa_volume_api_set_main_output_volume_control(u->volume_api, NULL);
-     }
-     if (u->input_volume_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
--        if (context) {
--            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);
--            pa_binding_target_info_free(info);
--        } else
--            pa_volume_api_set_main_input_volume_control(api, NULL);
-+        if (context)
-+            pa_volume_api_set_main_input_volume_control(u->volume_api, context->main_input_volume_control);
-+        else
-+            pa_volume_api_set_main_input_volume_control(u->volume_api, NULL);
-     }
-     if (u->output_mute_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
--        if (context) {
--            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);
--            pa_binding_target_info_free(info);
--        } else
--            pa_volume_api_set_main_output_mute_control(api, NULL);
-+        if (context)
-+            pa_volume_api_set_main_output_mute_control(u->volume_api, context->main_output_mute_control);
-+        else
-+            pa_volume_api_set_main_output_mute_control(u->volume_api, NULL);
-     }
-     if (u->input_mute_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) {
--        if (context) {
--            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);
--            pa_binding_target_info_free(info);
--        } else
--            pa_volume_api_set_main_input_mute_control(api, NULL);
-+        if (context)
-+            pa_volume_api_set_main_input_mute_control(u->volume_api, context->main_input_mute_control);
-+        else
-+            pa_volume_api_set_main_input_mute_control(u->volume_api, NULL);
-+    }
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static void handle_context_control_change(struct context *context, enum control_type type, pa_direction_t direction) {
-+    struct control_info *info;
-+
-+    pa_assert(context);
-+
-+    info = context_get_control_info(context, type, direction);
-+
-+    if (*info->model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT
-+            && context->userdata->main_volume_policy->active_main_volume_context == context->main_volume_context)
-+        info->set_volume_api_control(context->userdata->volume_api, *info->control);
-+}
-+
-+static pa_hook_result_t main_volume_context_main_output_volume_control_changed_cb(void *hook_data, void *call_data,
-+                                                                                  void *userdata) {
-+    pa_main_volume_context *context = call_data;
-+
-+    pa_assert(context);
-+
-+    handle_context_control_change(context->userdata, CONTROL_TYPE_VOLUME, PA_DIRECTION_OUTPUT);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t main_volume_context_main_input_volume_control_changed_cb(void *hook_data, void *call_data,
-+                                                                                 void *userdata) {
-+    pa_main_volume_context *context = call_data;
-+
-+    pa_assert(context);
-+
-+    handle_context_control_change(context->userdata, CONTROL_TYPE_VOLUME, PA_DIRECTION_INPUT);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t main_volume_context_main_output_mute_control_changed_cb(void *hook_data, void *call_data,
-+                                                                                void *userdata) {
-+    pa_main_volume_context *context = call_data;
-+
-+    pa_assert(context);
-+
-+    handle_context_control_change(context->userdata, CONTROL_TYPE_MUTE, PA_DIRECTION_OUTPUT);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t main_volume_context_main_input_mute_control_changed_cb(void *hook_data, void *call_data,
-+                                                                               void *userdata) {
-+    pa_main_volume_context *context = call_data;
-+
-+    pa_assert(context);
-+
-+    handle_context_control_change(context->userdata, CONTROL_TYPE_MUTE, PA_DIRECTION_INPUT);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t audio_group_put_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_audio_group *group = call_data;
-+    struct context *context;
-+    void *state;
-+
-+    pa_assert(u);
-+    pa_assert(group);
-+
-+    PA_HASHMAP_FOREACH(context, u->contexts, state) {
-+        if (context->output_volume_info.binding_target_name
-+                && pa_streq(context->output_volume_info.binding_target_name, group->name))
-+            context_set_binding_target(context, CONTROL_TYPE_VOLUME, PA_DIRECTION_OUTPUT, group);
-+
-+        if (context->input_volume_info.binding_target_name
-+                && pa_streq(context->input_volume_info.binding_target_name, group->name))
-+            context_set_binding_target(context, CONTROL_TYPE_VOLUME, PA_DIRECTION_INPUT, group);
-+
-+        if (context->output_mute_info.binding_target_name
-+                && pa_streq(context->output_mute_info.binding_target_name, group->name))
-+            context_set_binding_target(context, CONTROL_TYPE_MUTE, PA_DIRECTION_OUTPUT, group);
-+
-+        if (context->input_mute_info.binding_target_name
-+                && pa_streq(context->input_mute_info.binding_target_name, group->name))
-+            context_set_binding_target(context, CONTROL_TYPE_MUTE, PA_DIRECTION_INPUT, group);
-+    }
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t audio_group_unlink_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_audio_group *group = call_data;
-+    struct context *context;
-+    void *state;
-+
-+    pa_assert(u);
-+    pa_assert(group);
-+
-+    PA_HASHMAP_FOREACH(context, u->contexts, state) {
-+        if (context->output_volume_info.binding_target == group)
-+            context_set_binding_target(context, CONTROL_TYPE_VOLUME, PA_DIRECTION_OUTPUT, NULL);
-+
-+        if (context->input_volume_info.binding_target == group)
-+            context_set_binding_target(context, CONTROL_TYPE_VOLUME, PA_DIRECTION_INPUT, NULL);
-+
-+        if (context->output_mute_info.binding_target == group)
-+            context_set_binding_target(context, CONTROL_TYPE_MUTE, PA_DIRECTION_OUTPUT, NULL);
-+
-+        if (context->input_mute_info.binding_target == group)
-+            context_set_binding_target(context, CONTROL_TYPE_MUTE, PA_DIRECTION_INPUT, NULL);
-     }
-     return PA_HOOK_OK;
- }
-+static void handle_audio_group_control_change(struct userdata *u, pa_audio_group *group, enum control_type type) {
-+    struct context *context;
-+    void *state;
-+
-+    pa_assert(u);
-+    pa_assert(group);
-+
-+    PA_HASHMAP_FOREACH(context, u->contexts, state) {
-+        switch (type) {
-+            case CONTROL_TYPE_VOLUME:
-+                if (context->output_volume_info.binding_target == group)
-+                    pa_main_volume_context_set_main_output_volume_control(context->main_volume_context, group->volume_control);
-+
-+                if (context->input_volume_info.binding_target == group)
-+                    pa_main_volume_context_set_main_input_volume_control(context->main_volume_context, group->volume_control);
-+                break;
-+
-+            case CONTROL_TYPE_MUTE:
-+                if (context->output_mute_info.binding_target == group)
-+                    pa_main_volume_context_set_main_output_mute_control(context->main_volume_context, group->mute_control);
-+
-+                if (context->input_mute_info.binding_target == group)
-+                    pa_main_volume_context_set_main_input_mute_control(context->main_volume_context, group->mute_control);
-+                break;
-+        }
-+    }
-+}
-+
-+static pa_hook_result_t audio_group_volume_control_changed_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_audio_group *group = call_data;
-+
-+    pa_assert(u);
-+    pa_assert(group);
-+
-+    handle_audio_group_control_change(u, group, CONTROL_TYPE_VOLUME);
-+
-+    return PA_HOOK_OK;
-+}
-+
-+static pa_hook_result_t audio_group_mute_control_changed_cb(void *hook_data, void *call_data, void *userdata) {
-+    struct userdata *u = userdata;
-+    pa_audio_group *group = call_data;
-+
-+    pa_assert(u);
-+    pa_assert(group);
-+
-+    handle_audio_group_control_change(u, group, CONTROL_TYPE_MUTE);
-+
-+    return PA_HOOK_OK;
-+}
-+
- static int parse_model(pa_config_parser_state *state) {
-     int r;
-@@ -315,105 +517,81 @@ static int parse_model(pa_config_parser_state *state) {
-     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) {
-+static int get_context(struct userdata *u, const char *section, struct context **_r) {
-     const char *name;
-     struct context *context;
-     pa_assert(u);
-     if (!section)
--        return NULL;
-+        return -PA_ERR_INVALID;
-     if (!pa_startswith(section, "MainVolumeContext "))
--        return NULL;
-+        return -PA_ERR_INVALID;
-     name = section + 18;
--    context = pa_hashmap_get(u->unused_contexts, name);
-+    context = pa_hashmap_get(u->contexts, name);
-     if (!context) {
--        context = context_new(u, name);
--        pa_hashmap_put(u->unused_contexts, context->name, context);
-+        int r;
-+
-+        r = context_new(u, name, &context);
-+        if (r < 0)
-+            return r;
-+
-+        pa_hashmap_put(u->contexts, (void *) context->main_volume_context->name, context);
-     }
--    return context;
-+    *_r = context;
-+    return 0;
- }
- static int parse_description(pa_config_parser_state *state) {
-     struct userdata *u;
-+    int r;
-     struct context *context;
-     pa_assert(state);
-     u = state->userdata;
--    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,
-+    r = get_context(u, state->section, &context);
-+    if (r < 0) {
-+        pa_log("[%s:%u] Couldn't get main volume context for section \"%s\".", state->filename, state->lineno,
-                pa_strnull(state->section));
-         return -PA_ERR_INVALID;
-     }
--    context_set_description(context, state->rvalue);
-+    pa_main_volume_context_set_description(context->main_volume_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) {
-+static int parse_control(pa_config_parser_state *state, enum control_type type, pa_direction_t direction) {
-     struct userdata *u;
-+    int r;
-     struct context *context;
-     pa_assert(state);
-     u = state->userdata;
--    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,
-+    r = get_context(u, state->section, &context);
-+    if (r < 0) {
-+        pa_log("[%s:%u] Couldn't get main volume context for section \"%s\".", state->filename, state->lineno,
-                pa_strnull(state->section));
-         return -PA_ERR_INVALID;
-     }
-     if (pa_streq(state->rvalue, "none"))
--        context_set_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_binding_target_name(context, type, direction, NULL);
-+    else if (pa_startswith(state->rvalue, BIND_PREFIX)) {
-+        if (pa_startswith(state->rvalue, BIND_AUDIO_GROUP_PREFIX))
-+            context_set_binding_target_name(context, type, direction, state->rvalue + strlen(BIND_AUDIO_GROUP_PREFIX));
-+        else {
-+            pa_log("[%s:%u] Failed to parse binding target \"%s\".", state->filename, state->lineno, state->rvalue + strlen(BIND_PREFIX));
-+            return -PA_ERR_INVALID;
-         }
--
--        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;
-@@ -425,69 +603,38 @@ static int parse_main_control(pa_config_parser_state *state, enum control_type t
- 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);
-+    return parse_control(state, CONTROL_TYPE_VOLUME, PA_DIRECTION_OUTPUT);
- }
- static int parse_main_input_volume_control(pa_config_parser_state *state) {
-     pa_assert(state);
--    return parse_main_control(state, CONTROL_TYPE_VOLUME, PA_DIRECTION_INPUT);
-+    return parse_control(state, CONTROL_TYPE_VOLUME, PA_DIRECTION_INPUT);
- }
- static int parse_main_output_mute_control(pa_config_parser_state *state) {
-     pa_assert(state);
--    return parse_main_control(state, CONTROL_TYPE_MUTE, PA_DIRECTION_OUTPUT);
-+    return parse_control(state, CONTROL_TYPE_MUTE, PA_DIRECTION_OUTPUT);
- }
- static int parse_main_input_mute_control(pa_config_parser_state *state) {
-     pa_assert(state);
--    return parse_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;
-+    return parse_control(state, CONTROL_TYPE_MUTE, PA_DIRECTION_INPUT);
- }
- int pa__init(pa_module *module) {
-     struct userdata *u;
-     FILE *f;
-     char *fn = NULL;
-+    struct context *context;
-+    void *state;
-     pa_assert(module);
-     u = module->userdata = pa_xnew0(struct userdata, 1);
-+    u->volume_api = pa_volume_api_get(module->core);
-     u->main_volume_policy = pa_main_volume_policy_get(module->core);
-     u->output_volume_model = MODEL_NONE;
-     u->input_volume_model = MODEL_NONE;
-@@ -498,9 +645,32 @@ int pa__init(pa_module *module) {
-     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);
-+    u->main_volume_context_main_output_volume_control_changed_slot =
-+            pa_hook_connect(&u->main_volume_policy->hooks
-+                                [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED],
-+                            PA_HOOK_NORMAL, main_volume_context_main_output_volume_control_changed_cb, u);
-+    u->main_volume_context_main_input_volume_control_changed_slot =
-+            pa_hook_connect(&u->main_volume_policy->hooks
-+                                [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_VOLUME_CONTROL_CHANGED],
-+                            PA_HOOK_NORMAL, main_volume_context_main_input_volume_control_changed_cb, u);
-+    u->main_volume_context_main_output_mute_control_changed_slot =
-+            pa_hook_connect(&u->main_volume_policy->hooks
-+                                [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_MUTE_CONTROL_CHANGED],
-+                            PA_HOOK_NORMAL, main_volume_context_main_output_mute_control_changed_cb, u);
-+    u->main_volume_context_main_input_mute_control_changed_slot =
-+            pa_hook_connect(&u->main_volume_policy->hooks
-+                                [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_MUTE_CONTROL_CHANGED],
-+                            PA_HOOK_NORMAL, main_volume_context_main_input_mute_control_changed_cb, u);
-+    u->audio_group_put_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_PUT], PA_HOOK_NORMAL,
-+                                              audio_group_put_cb, u);
-+    u->audio_group_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK], PA_HOOK_NORMAL,
-+                                                 audio_group_unlink_cb, u);
-+    u->audio_group_volume_control_changed_slot =
-+            pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_VOLUME_CONTROL_CHANGED], PA_HOOK_NORMAL,
-+                            audio_group_volume_control_changed_cb, u);
-+    u->audio_group_mute_control_changed_slot =
-+            pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_MUTE_CONTROL_CHANGED], PA_HOOK_NORMAL,
-+                            audio_group_mute_control_changed_cb, u);
-     f = pa_open_config_file(PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "main-volume-policy.conf", "main-volume-policy.conf", NULL, &fn);
-     if (f) {
-@@ -509,7 +679,6 @@ int pa__init(pa_module *module) {
-             { "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 },
-@@ -525,7 +694,8 @@ int pa__init(pa_module *module) {
-         f = NULL;
-     }
--    finalize_config(u);
-+    PA_HASHMAP_FOREACH(context, u->contexts, state)
-+        context_put(context);
-     pa_log_debug("Output volume model: %s", model_to_string(u->output_volume_model));
-     pa_log_debug("Input volume model: %s", model_to_string(u->input_volume_model));
-@@ -544,6 +714,30 @@ void pa__done(pa_module *module) {
-     if (!u)
-         return;
-+    if (u->audio_group_mute_control_changed_slot)
-+        pa_hook_slot_free(u->audio_group_mute_control_changed_slot);
-+
-+    if (u->audio_group_volume_control_changed_slot)
-+        pa_hook_slot_free(u->audio_group_volume_control_changed_slot);
-+
-+    if (u->audio_group_unlink_slot)
-+        pa_hook_slot_free(u->audio_group_unlink_slot);
-+
-+    if (u->audio_group_put_slot)
-+        pa_hook_slot_free(u->audio_group_put_slot);
-+
-+    if (u->main_volume_context_main_input_mute_control_changed_slot)
-+        pa_hook_slot_free(u->main_volume_context_main_input_mute_control_changed_slot);
-+
-+    if (u->main_volume_context_main_output_mute_control_changed_slot)
-+        pa_hook_slot_free(u->main_volume_context_main_output_mute_control_changed_slot);
-+
-+    if (u->main_volume_context_main_input_volume_control_changed_slot)
-+        pa_hook_slot_free(u->main_volume_context_main_input_volume_control_changed_slot);
-+
-+    if (u->main_volume_context_main_output_volume_control_changed_slot)
-+        pa_hook_slot_free(u->main_volume_context_main_output_volume_control_changed_slot);
-+
-     if (u->active_main_volume_context_changed_slot)
-         pa_hook_slot_free(u->active_main_volume_context_changed_slot);
-@@ -553,5 +747,8 @@ void pa__done(pa_module *module) {
-     if (u->main_volume_policy)
-         pa_main_volume_policy_unref(u->main_volume_policy);
-+    if (u->volume_api)
-+        pa_volume_api_unref(u->volume_api);
-+
-     pa_xfree(u);
- }
-diff --git a/src/modules/volume-api/audio-group.c b/src/modules/volume-api/audio-group.c
-index 76bfa69..66e0f8a 100644
---- a/src/modules/volume-api/audio-group.c
-+++ b/src/modules/volume-api/audio-group.c
-@@ -29,34 +29,33 @@
- #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 pa_audio_group_new(pa_volume_api *api, const char *name, pa_audio_group **_r) {
-+    pa_audio_group *group = NULL;
-     int r;
-     pa_assert(api);
-     pa_assert(name);
--    pa_assert(description);
--    pa_assert(group);
-+    pa_assert(_r);
--    group_local = pa_xnew0(pa_audio_group, 1);
--    group_local->volume_api = api;
--    group_local->index = pa_volume_api_allocate_audio_group_index(api);
-+    group = pa_xnew0(pa_audio_group, 1);
-+    group->volume_api = api;
-+    group->index = pa_volume_api_allocate_audio_group_index(api);
--    r = pa_volume_api_register_name(api, name, true, &group_local->name);
-+    r = pa_volume_api_register_name(api, name, true, &group->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;
-+    group->description = pa_xstrdup(group->name);
-+    group->proplist = pa_proplist_new();
-+    group->volume_streams = pa_hashmap_new(NULL, NULL);
-+    group->mute_streams = pa_hashmap_new(NULL, NULL);
-+    *_r = group;
-     return 0;
- fail:
--    pa_audio_group_free(group_local);
-+    if (group)
-+        pa_audio_group_free(group);
-     return r;
- }
-@@ -68,7 +67,6 @@ void pa_audio_group_put(pa_audio_group *group) {
-     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);
-@@ -99,9 +97,9 @@ void pa_audio_group_unlink(pa_audio_group *group) {
-     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);
--    pa_volume_api_remove_audio_group(group->volume_api, group);
-+    pa_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK], group);
-     while ((stream = pa_hashmap_first(group->mute_streams)))
-         pas_stream_set_audio_group_for_mute(stream, NULL);
-@@ -109,34 +107,15 @@ void pa_audio_group_unlink(pa_audio_group *group) {
-     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;
--    }
-+    pa_audio_group_set_mute_control(group, NULL);
-+    pa_audio_group_set_volume_control(group, NULL);
- }
- void pa_audio_group_free(pa_audio_group *group) {
-     pa_assert(group);
--    if (!group->unlinked)
-+    /* unlink() expects name to be set. */
-+    if (!group->unlinked && group->name)
-         pa_audio_group_unlink(group);
-     if (group->mute_streams)
-@@ -156,133 +135,33 @@ void pa_audio_group_free(pa_audio_group *group) {
-     pa_xfree(group);
- }
--const char *pa_audio_group_get_name(pa_audio_group *group) {
--    pa_assert(group);
-+void pa_audio_group_set_description(pa_audio_group *group, const char *description) {
-+    char *old_description;
--    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);
-+    pa_assert(description);
--    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;
-+    old_description = group->description;
--    pa_assert(control);
-+    if (pa_streq(description, old_description))
-+        return;
--    group = control->userdata;
-+    group->description = pa_xstrdup(description);
--    PA_HASHMAP_FOREACH(stream, group->mute_streams, state) {
--        if (stream->own_mute_control)
--            pa_mute_control_set_mute(stream->own_mute_control, control->mute);
-+    if (!group->linked || group->unlinked) {
-+        pa_xfree(old_description);
-+        return;
-     }
--}
--void pa_audio_group_set_have_own_mute_control(pa_audio_group *group, bool have) {
--    pa_assert(group);
-+    pa_log_debug("The description of audio group %s changed from \"%s\" to \"%s\".", group->name, old_description,
-+                 description);
-+    pa_xfree(old_description);
--    if (have == group->have_own_mute_control)
--        return;
-+    pa_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_DESCRIPTION_CHANGED], group);
--    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) {
-+void pa_audio_group_set_volume_control(pa_audio_group *group, pa_volume_control *control) {
-     pa_volume_control *old_control;
-     pa_assert(group);
-@@ -292,14 +171,8 @@ static void set_volume_control_internal(pa_audio_group *group, pa_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;
-@@ -309,18 +182,7 @@ static void set_volume_control_internal(pa_audio_group *group, pa_volume_control
-     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) {
-+void pa_audio_group_set_mute_control(pa_audio_group *group, pa_mute_control *control) {
-     pa_mute_control *old_control;
-     pa_assert(group);
-@@ -330,14 +192,8 @@ static void set_mute_control_internal(pa_audio_group *group, pa_mute_control *co
-     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;
-@@ -347,57 +203,11 @@ static void set_mute_control_internal(pa_audio_group *group, pa_mute_control *co
-     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) {
-@@ -405,8 +215,6 @@ void pa_audio_group_remove_volume_stream(pa_audio_group *group, pas_stream *stre
-     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) {
-@@ -414,11 +222,6 @@ void pa_audio_group_add_mute_stream(pa_audio_group *group, pas_stream *stream) {
-     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) {
-@@ -426,23 +229,4 @@ void pa_audio_group_remove_mute_stream(pa_audio_group *group, pas_stream *stream
-     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
-index 41591ba..02db3eb 100644
---- a/src/modules/volume-api/audio-group.h
-+++ b/src/modules/volume-api/audio-group.h
-@@ -22,7 +22,6 @@
-   USA.
- ***/
--#include <modules/volume-api/binding.h>
- #include <modules/volume-api/mute-control.h>
- #include <modules/volume-api/volume-control.h>
-@@ -32,10 +31,6 @@
- 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;
-@@ -44,13 +39,7 @@ struct pa_audio_group {
-     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) */
-@@ -58,28 +47,22 @@ struct pa_audio_group {
-     bool unlinked;
- };
--int pa_audio_group_new(pa_volume_api *api, const char *name, const char *description, pa_audio_group **group);
-+int pa_audio_group_new(pa_volume_api *api, const char *name, pa_audio_group **_r);
- void pa_audio_group_put(pa_audio_group *group);
- void pa_audio_group_unlink(pa_audio_group *group);
- void pa_audio_group_free(pa_audio_group *group);
--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);
-+/* Called by the audio group implementation. */
-+void pa_audio_group_set_description(pa_audio_group *group, const char *description);
- void pa_audio_group_set_volume_control(pa_audio_group *group, pa_volume_control *control);
- void pa_audio_group_set_mute_control(pa_audio_group *group, pa_mute_control *control);
--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. */
-+/* Called by sstream.c only. If you want to assign a stream to an audio group, use
-+ * pas_stream_set_audio_group_for_volume() and
-+ * pas_stream_set_audio_group_for_mute(). */
- void pa_audio_group_add_volume_stream(pa_audio_group *group, pas_stream *stream);
- void pa_audio_group_remove_volume_stream(pa_audio_group *group, pas_stream *stream);
- void pa_audio_group_add_mute_stream(pa_audio_group *group, pas_stream *stream);
- void pa_audio_group_remove_mute_stream(pa_audio_group *group, pas_stream *stream);
--/* 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
-deleted file mode 100644
-index 6e73119..0000000
---- a/src/modules/volume-api/binding.c
-+++ /dev/null
-@@ -1,386 +0,0 @@
--/***
--  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
-deleted file mode 100644
-index ba4dea8..0000000
---- a/src/modules/volume-api/binding.h
-+++ /dev/null
-@@ -1,128 +0,0 @@
--#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
-index 0317fb6..75545dd 100644
---- a/src/modules/volume-api/bvolume.h
-+++ b/src/modules/volume-api/bvolume.h
-@@ -29,13 +29,16 @@ typedef pa_ext_volume_api_bvolume pa_bvolume;
- #define pa_balance_valid pa_ext_volume_api_balance_valid
- #define pa_bvolume_valid pa_ext_volume_api_bvolume_valid
- #define pa_bvolume_init_invalid pa_ext_volume_api_bvolume_init_invalid
-+#define pa_bvolume_init pa_ext_volume_api_bvolume_init
- #define pa_bvolume_init_mono pa_ext_volume_api_bvolume_init_mono
-+#define pa_bvolume_parse_balance pa_ext_volume_api_bvolume_parse_balance
- #define pa_bvolume_equal pa_ext_volume_api_bvolume_equal
- #define pa_bvolume_from_cvolume pa_ext_volume_api_bvolume_from_cvolume
- #define pa_bvolume_to_cvolume pa_ext_volume_api_bvolume_to_cvolume
- #define pa_bvolume_copy_balance pa_ext_volume_api_bvolume_copy_balance
- #define pa_bvolume_reset_balance pa_ext_volume_api_bvolume_reset_balance
- #define pa_bvolume_remap pa_ext_volume_api_bvolume_remap
-+#define pa_bvolume_balance_to_string pa_ext_volume_api_bvolume_balance_to_string
- #define PA_BVOLUME_SNPRINT_BALANCE_MAX PA_EXT_VOLUME_API_BVOLUME_SNPRINT_BALANCE_MAX
- #define pa_bvolume_snprint_balance pa_ext_volume_api_bvolume_snprint_balance
-diff --git a/src/modules/volume-api/device-creator.c b/src/modules/volume-api/device-creator.c
-index f35fab0..fc486f8 100644
---- a/src/modules/volume-api/device-creator.c
-+++ b/src/modules/volume-api/device-creator.c
-@@ -59,6 +59,8 @@ struct device_volume_control {
-     pa_hook_slot *volume_changed_slot;
- };
-+static void device_volume_control_free(struct device_volume_control *control);
-+
- struct device_mute_control {
-     struct device *device;
-     pa_mute_control *mute_control;
-@@ -68,6 +70,8 @@ struct device_mute_control {
-     pa_hook_slot *mute_changed_slot;
- };
-+static void device_mute_control_free(struct device_mute_control *control);
-+
- struct device {
-     pa_device_creator *creator;
-     enum device_type type;
-@@ -85,6 +89,8 @@ struct device {
-     struct device *monitor;
- };
-+static void device_free(struct device *device);
-+
- static const char *device_type_from_icon_name(const char *icon_name) {
-     if (!icon_name)
-         return NULL;
-@@ -168,112 +174,6 @@ static const char *get_source_description(pa_source *source) {
-     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;
-@@ -309,24 +209,55 @@ static pa_hook_result_t sink_or_source_volume_changed_cb(void *hook_data, void *
-     if (sink)
-         pa_bvolume_from_cvolume(&bvolume, &sink->reference_volume, &sink->channel_map);
--    else
-+    else if (source)
-         pa_bvolume_from_cvolume(&bvolume, &source->reference_volume, &source->channel_map);
-+    else
-+        pa_assert_not_reached();
--    pa_volume_control_volume_changed(control->volume_control, &bvolume, true, true);
-+    pa_volume_control_set_volume(control->volume_control, &bvolume, true, true);
-     return PA_HOOK_OK;
- }
--static void volume_control_set_initial_volume_cb(pa_volume_control *c) {
-+static int volume_control_set_volume_cb(pa_volume_control *c, const pa_bvolume *original_volume,
-+                                        const pa_bvolume *remapped_volume, bool set_volume, bool set_balance) {
-     struct device_volume_control *control;
-     struct device *device;
-+    pa_bvolume bvolume;
-     pa_cvolume cvolume;
-     pa_assert(c);
-+    pa_assert(original_volume);
-+    pa_assert(remapped_volume);
-     control = c->userdata;
-     device = control->device;
--    pa_bvolume_to_cvolume(&control->volume_control->volume, &cvolume);
-+
-+    switch (device->type) {
-+        case DEVICE_TYPE_PORT:
-+            if (device->port->direction == PA_DIRECTION_OUTPUT)
-+                pa_bvolume_from_cvolume(&bvolume, &device->sink->reference_volume, &device->sink->channel_map);
-+            else
-+                pa_bvolume_from_cvolume(&bvolume, &device->source->reference_volume, &device->source->channel_map);
-+            break;
-+
-+        case DEVICE_TYPE_SINK:
-+            pa_bvolume_from_cvolume(&bvolume, &device->sink->reference_volume, &device->sink->channel_map);
-+            break;
-+
-+        case DEVICE_TYPE_PORT_MONITOR:
-+        case DEVICE_TYPE_SOURCE:
-+            pa_bvolume_from_cvolume(&bvolume, &device->source->reference_volume, &device->source->channel_map);
-+            break;
-+    }
-+
-+    if (set_volume)
-+        bvolume.volume = remapped_volume->volume;
-+
-+    if (set_balance)
-+        pa_bvolume_copy_balance(&bvolume, remapped_volume);
-+
-+    pa_bvolume_to_cvolume(&bvolume, &cvolume);
-     switch (device->type) {
-         case DEVICE_TYPE_PORT:
-@@ -345,44 +276,91 @@ static void volume_control_set_initial_volume_cb(pa_volume_control *c) {
-             pa_sink_set_volume(device->sink, &cvolume, true, true);
-             break;
-     }
-+
-+    return 0;
- }
--static void device_volume_control_put(struct device_volume_control *control) {
--    struct device *device;
-+static int device_volume_control_new(struct device *device, struct device_volume_control **_r) {
-+    struct device_volume_control *control = NULL;
-+    const char *name = NULL;
-     pa_bvolume volume;
-+    bool convertible_to_dB = false;
-+    int r;
--    pa_assert(control);
-+    pa_assert(device);
-+    pa_assert(_r);
--    device = control->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) {
-                 control->volume_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED],
-                                                                PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control);
-                 pa_bvolume_from_cvolume(&volume, &device->sink->reference_volume, &device->sink->channel_map);
-+                convertible_to_dB = device->sink->flags & PA_SINK_DECIBEL_VOLUME;
-             } else {
-                 control->volume_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED],
-                                                                PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control);
-                 pa_bvolume_from_cvolume(&volume, &device->source->reference_volume, &device->source->channel_map);
-+                convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME;
-             }
-+
-             break;
-         case DEVICE_TYPE_PORT_MONITOR:
--        case DEVICE_TYPE_SOURCE:
-+            name = "port-monitor-volume-control";
-             control->volume_changed_slot = pa_hook_connect(&device->source->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED],
-                                                            PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control);
-             pa_bvolume_from_cvolume(&volume, &device->source->reference_volume, &device->source->channel_map);
-+            convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME;
-             break;
-         case DEVICE_TYPE_SINK:
-+            name = "sink-volume-control";
-             control->volume_changed_slot = pa_hook_connect(&device->sink->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED],
-                                                            PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control);
-             pa_bvolume_from_cvolume(&volume, &device->sink->reference_volume, &device->sink->channel_map);
-+            convertible_to_dB = device->sink->flags & PA_SINK_DECIBEL_VOLUME;
-+            break;
-+
-+        case DEVICE_TYPE_SOURCE:
-+            name = "source-volume-control";
-+            control->volume_changed_slot = pa_hook_connect(&device->source->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED],
-+                                                           PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control);
-+            pa_bvolume_from_cvolume(&volume, &device->source->reference_volume, &device->source->channel_map);
-+            convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME;
-             break;
-     }
--    pa_volume_control_put(control->volume_control, &volume, volume_control_set_initial_volume_cb);
-+    r = pa_volume_control_new(device->creator->volume_api, name, false, &control->volume_control);
-+    if (r < 0)
-+        goto fail;
-+
-+    pa_volume_control_set_description(control->volume_control, device->device->description);
-+    pa_volume_control_set_channel_map(control->volume_control, &volume.channel_map);
-+    pa_volume_control_set_volume(control->volume_control, &volume, true, true);
-+    pa_volume_control_set_convertible_to_dB(control->volume_control, convertible_to_dB);
-+    control->volume_control->set_volume = volume_control_set_volume_cb;
-+    control->volume_control->userdata = control;
-+
-+    *_r = control;
-+    return 0;
-+
-+fail:
-+    if (control)
-+        device_volume_control_free(control);
-+
-+    return r;
-+}
-+
-+static void device_volume_control_put(struct device_volume_control *control) {
-+    pa_assert(control);
-+
-+    pa_volume_control_put(control->volume_control);
- }
- static void device_volume_control_unlink(struct device_volume_control *control) {
-@@ -395,11 +373,6 @@ static void device_volume_control_unlink(struct device_volume_control *control)
-     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) {
-@@ -411,71 +384,10 @@ static void device_volume_control_free(struct device_volume_control *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;
-+    if (control->volume_changed_slot)
-+        pa_hook_slot_free(control->volume_changed_slot);
--    return control;
-+    pa_xfree(control);
- }
- static pa_hook_result_t sink_or_source_mute_changed_cb(void *hook_data, void *call_data, void *userdata) {
-@@ -518,13 +430,13 @@ static pa_hook_result_t sink_or_source_mute_changed_cb(void *hook_data, void *ca
-     else
-         pa_assert_not_reached();
--    pa_mute_control_mute_changed(control->mute_control, mute);
-+    pa_mute_control_set_mute(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;
-+static int mute_control_set_mute_cb(pa_mute_control *c, bool mute) {
-+    struct device_mute_control *control;
-     struct device *device;
-     pa_assert(c);
-@@ -535,32 +447,40 @@ static void mute_control_set_initial_mute_cb(pa_mute_control *c) {
-     switch (device->type) {
-         case DEVICE_TYPE_PORT:
-             if (device->port->direction == PA_DIRECTION_OUTPUT)
--                pa_sink_set_mute(device->sink, c->mute, true);
-+                pa_sink_set_mute(device->sink, mute, true);
-             else
--                pa_source_set_mute(device->source, c->mute, true);
-+                pa_source_set_mute(device->source, mute, true);
-             break;
-         case DEVICE_TYPE_PORT_MONITOR:
-         case DEVICE_TYPE_SOURCE:
--            pa_source_set_mute(device->source, c->mute, true);
-+            pa_source_set_mute(device->source, mute, true);
-             break;
-         case DEVICE_TYPE_SINK:
--            pa_sink_set_mute(device->sink, c->mute, true);
-+            pa_sink_set_mute(device->sink, mute, true);
-             break;
-     }
-+
-+    return 0;
- }
--static void device_mute_control_put(struct device_mute_control *control) {
--    struct device *device;
-+static int device_mute_control_new(struct device *device, struct device_mute_control **_r) {
-+    struct device_mute_control *control = NULL;
-+    const char *name = NULL;
-     bool mute = false;
-+    int r;
--    pa_assert(control);
-+    pa_assert(device);
-+    pa_assert(_r);
--    device = control->device;
-+    control = pa_xnew0(struct device_mute_control, 1);
-+    control->device = device;
-     switch (device->type) {
-         case DEVICE_TYPE_PORT:
-+            name = "port-mute-control";
-+
-             if (device->port->direction == PA_DIRECTION_OUTPUT) {
-                 control->mute_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SINK_MUTE_CHANGED],
-                                                              PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control);
-@@ -573,20 +493,50 @@ static void device_mute_control_put(struct device_mute_control *control) {
-             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],
-+            name = "port-monitor-mute-control";
-+            control->mute_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SOURCE_MUTE_CHANGED],
-                                                          PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control);
-             mute = device->source->muted;
-             break;
-         case DEVICE_TYPE_SINK:
-+            name = "sink-mute-control";
-             control->mute_changed_slot = pa_hook_connect(&device->sink->core->hooks[PA_CORE_HOOK_SINK_MUTE_CHANGED],
-                                                          PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control);
-             mute = device->sink->muted;
-             break;
-+
-+        case DEVICE_TYPE_SOURCE:
-+            name = "source-mute-control";
-+            control->mute_changed_slot = pa_hook_connect(&device->source->core->hooks[PA_CORE_HOOK_SOURCE_MUTE_CHANGED],
-+                                                         PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control);
-+            mute = device->source->muted;
-+            break;
-     }
--    pa_mute_control_put(control->mute_control, mute, true, mute_control_set_initial_mute_cb);
-+    r = pa_mute_control_new(device->creator->volume_api, name, false, &control->mute_control);
-+    if (r < 0)
-+        goto fail;
-+
-+    pa_mute_control_set_description(control->mute_control, device->device->description);
-+    pa_mute_control_set_mute(control->mute_control, mute);
-+    control->mute_control->set_mute = mute_control_set_mute_cb;
-+    control->mute_control->userdata = control;
-+
-+    *_r = control;
-+    return 0;
-+
-+fail:
-+    if (control)
-+        device_mute_control_free(control);
-+
-+    return r;
-+}
-+
-+static void device_mute_control_put(struct device_mute_control *control) {
-+    pa_assert(control);
-+
-+    pa_mute_control_put(control->mute_control);
- }
- static void device_mute_control_unlink(struct device_mute_control *control) {
-@@ -599,11 +549,6 @@ static void device_mute_control_unlink(struct device_mute_control *control) {
-     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) {
-@@ -615,6 +560,9 @@ static void device_mute_control_free(struct device_mute_control *control) {
-     if (control->mute_control)
-         pa_mute_control_free(control->mute_control);
-+    if (control->mute_changed_slot)
-+        pa_hook_slot_free(control->mute_changed_slot);
-+
-     pa_xfree(control);
- }
-@@ -707,22 +655,24 @@ static pa_hook_result_t sink_or_source_proplist_changed_cb(void *hook_data, void
-     }
-     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);
-+    pa_volume_control_set_description(device->volume_control->volume_control, description);
-+    pa_mute_control_set_description(device->mute_control->mute_control, description);
-     return PA_HOOK_OK;
- }
--static struct device *device_new(pa_device_creator *creator, enum device_type type, void *core_device) {
-+static int device_new(pa_device_creator *creator, enum device_type type, void *core_device, struct device **_r) {
-     struct device *device = NULL;
-     const char *name = NULL;
-     char *description = NULL;
-     pa_direction_t direction = PA_DIRECTION_OUTPUT;
-     const char *device_type = NULL;
-     bool create_volume_and_mute_controls = true;
-+    int r;
-     pa_assert(creator);
-     pa_assert(core_device);
-+    pa_assert(_r);
-     device = pa_xnew0(struct device, 1);
-     device->creator = creator;
-@@ -767,18 +717,20 @@ static struct device *device_new(pa_device_creator *creator, enum device_type ty
-             break;
-     }
--    device->device = pa_device_new(creator->volume_api, name, description, direction, &device_type, device_type ? 1 : 0);
-+    r = pa_device_new(creator->volume_api, name, description, direction, &device_type, device_type ? 1 : 0, &device->device);
-     pa_xfree(description);
-+    if (r < 0)
-+        goto fail;
-     if (create_volume_and_mute_controls) {
--        device->volume_control = device_volume_control_new(device);
--        device->mute_control = device_mute_control_new(device);
-+        device_volume_control_new(device, &device->volume_control);
-+        device_mute_control_new(device, &device->mute_control);
-     }
-     switch (type) {
-         case DEVICE_TYPE_PORT:
-             if (device->port->direction == PA_DIRECTION_OUTPUT)
--                device->monitor = device_new(creator, DEVICE_TYPE_PORT_MONITOR, device->port);
-+                device_new(creator, DEVICE_TYPE_PORT_MONITOR, device->port, &device->monitor);
-             break;
-         case DEVICE_TYPE_PORT_MONITOR:
-@@ -795,7 +747,14 @@ static struct device *device_new(pa_device_creator *creator, enum device_type ty
-             break;
-     }
--    return device;
-+    *_r = device;
-+    return 0;
-+
-+fail:
-+    if (device)
-+        device_free(device);
-+
-+    return r;
- }
- static pa_hook_result_t port_active_changed_cb(void *hook_data, void *call_data, void *userdata) {
-@@ -825,25 +784,36 @@ static pa_hook_result_t port_active_changed_cb(void *hook_data, void *call_data,
-             pa_assert_not_reached();
-     }
--    if (should_have_volume_and_mute_controls && !device->volume_control) {
--        pa_assert(!device->mute_control);
-+    if (should_have_volume_and_mute_controls) {
-+        int r;
--        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);
-+        if (!device->volume_control) {
-+            r = device_volume_control_new(device, &device->volume_control);
-+            if (r >= 0) {
-+                device_volume_control_put(device->volume_control);
-+                pa_device_set_default_volume_control(device->device, device->volume_control->volume_control);
-+            }
-+        }
--        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 (!device->mute_control) {
-+            r = device_mute_control_new(device, &device->mute_control);
-+            if (r >= 0) {
-+                device_mute_control_put(device->mute_control);
-+                pa_device_set_default_mute_control(device->device, device->mute_control->mute_control);
-+            }
-+        }
-     }
--    if (!should_have_volume_and_mute_controls && device->volume_control) {
--        pa_assert(device->mute_control);
-+    if (!should_have_volume_and_mute_controls) {
-+        if (device->mute_control) {
-+            device_mute_control_free(device->mute_control);
-+            device->mute_control = NULL;
-+        }
--        device_mute_control_free(device->mute_control);
--        device->mute_control = NULL;
--        device_volume_control_free(device->volume_control);
--        device->volume_control = NULL;
-+        if (device->volume_control) {
-+            device_volume_control_free(device->volume_control);
-+            device->volume_control = NULL;
-+        }
-     }
-     return PA_HOOK_OK;
-@@ -928,6 +898,7 @@ static void device_free(struct device *device) {
- static void create_device(pa_device_creator *creator, enum device_type type, void *core_device) {
-     struct device *device;
-+    int r;
-     pa_assert(creator);
-     pa_assert(core_device);
-@@ -956,9 +927,11 @@ static void create_device(pa_device_creator *creator, enum device_type type, voi
-         }
-     }
--    device = device_new(creator, type, core_device);
--    pa_hashmap_put(creator->devices, core_device, device);
--    device_put(device);
-+    r = device_new(creator, type, core_device, &device);
-+    if (r >= 0) {
-+        pa_hashmap_put(creator->devices, core_device, device);
-+        device_put(device);
-+    }
- }
- static pa_hook_result_t card_put_cb(void *hook_data, void *call_data, void *userdata) {
-diff --git a/src/modules/volume-api/device.c b/src/modules/volume-api/device.c
-index ea496ba..c1a580c 100644
---- a/src/modules/volume-api/device.c
-+++ b/src/modules/volume-api/device.c
-@@ -32,20 +32,26 @@
- #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;
-+int pa_device_new(pa_volume_api *api, const char *name, const char *description, pa_direction_t direction,
-+                  const char * const *device_types, unsigned n_device_types, pa_device **_r) {
-+    pa_device *device = NULL;
-+    int r;
-     unsigned i;
-     pa_assert(api);
-     pa_assert(name);
-     pa_assert(description);
-     pa_assert(device_types || n_device_types == 0);
-+    pa_assert(_r);
-     device = pa_xnew0(pa_device, 1);
-     device->volume_api = api;
-     device->index = pa_volume_api_allocate_device_index(api);
--    pa_assert_se(pa_volume_api_register_name(api, name, false, &device->name) >= 0);
-+
-+    r = pa_volume_api_register_name(api, name, false, &device->name);
-+    if (r < 0)
-+        goto fail;
-+
-     device->description = pa_xstrdup(description);
-     device->direction = direction;
-     device->device_types = pa_dynarray_new(pa_xfree);
-@@ -57,7 +63,14 @@ pa_device *pa_device_new(pa_volume_api *api, const char *name, const char *descr
-     device->use_default_volume_control = true;
-     device->use_default_mute_control = true;
--    return device;
-+    *_r = device;
-+    return 0;
-+
-+fail:
-+    if (device)
-+        pa_device_free(device);
-+
-+    return r;
- }
- void pa_device_put(pa_device *device, pa_volume_control *default_volume_control, pa_mute_control *default_mute_control) {
-@@ -84,7 +97,6 @@ void pa_device_put(pa_device *device, pa_volume_control *default_volume_control,
-     }
-     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),
-@@ -120,35 +132,21 @@ void pa_device_unlink(pa_device *device) {
-     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);
-+        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;
--    }
-+    pa_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_UNLINK], device);
--    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;
--    }
-+    pa_device_set_mute_control(device, NULL);
-+    pa_device_set_default_mute_control(device, NULL);
-+    pa_device_set_volume_control(device, NULL);
-+    pa_device_set_default_volume_control(device, NULL);
- }
- void pa_device_free(pa_device *device) {
-     pa_assert(device);
--    if (!device->unlinked)
-+    /* unlink() expects name to be set. */
-+    if (!device->unlinked && device->name)
-         pa_device_unlink(device);
-     if (device->proplist)
-diff --git a/src/modules/volume-api/device.h b/src/modules/volume-api/device.h
-index 9eac7e9..8bd5158 100644
---- a/src/modules/volume-api/device.h
-+++ b/src/modules/volume-api/device.h
-@@ -51,8 +51,8 @@ struct pa_device {
-     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);
-+int pa_device_new(pa_volume_api *api, const char *name, const char *description, pa_direction_t direction,
-+                  const char * const *device_types, unsigned n_device_types, pa_device **_r);
- void pa_device_put(pa_device *device, pa_volume_control *default_volume_control, pa_mute_control *default_mute_control);
- void pa_device_unlink(pa_device *device);
- void pa_device_free(pa_device *device);
-diff --git a/src/modules/volume-api/inidb.c b/src/modules/volume-api/inidb.c
-new file mode 100644
-index 0000000..8116e72
---- /dev/null
-+++ b/src/modules/volume-api/inidb.c
-@@ -0,0 +1,553 @@
-+/***
-+  This file is part of PulseAudio.
-+
-+  Copyright 2014 Intel Corporation
-+
-+  PulseAudio is free software; you can redistribute it and/or modify
-+  it under the terms of the GNU Lesser General Public License as published
-+  by the Free Software Foundation; either version 2.1 of the License,
-+  or (at your option) any later version.
-+
-+  PulseAudio is distributed in the hope that it will be useful, but
-+  WITHOUT ANY WARRANTY; without even the implied warranty of
-+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+  General Public License for more details.
-+
-+  You should have received a copy of the GNU Lesser General Public License
-+  along with PulseAudio; if not, write to the Free Software
-+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-+  USA.
-+***/
-+
-+#ifdef HAVE_CONFIG_H
-+#include <config.h>
-+#endif
-+
-+#include "inidb.h"
-+
-+#include <pulse/mainloop-api.h>
-+#include <pulse/rtclock.h>
-+#include <pulse/timeval.h>
-+#include <pulse/xmalloc.h>
-+
-+#include <pulsecore/conf-parser.h>
-+#include <pulsecore/core-error.h>
-+#include <pulsecore/core-rtclock.h>
-+#include <pulsecore/core-util.h>
-+#include <pulsecore/hashmap.h>
-+#include <pulsecore/macro.h>
-+#include <pulsecore/namereg.h>
-+
-+#include <errno.h>
-+
-+#define SAVE_INTERVAL_USEC (10 * PA_USEC_PER_SEC)
-+
-+struct pa_inidb {
-+    pa_core *core;
-+    char *name;
-+    char *file_path;
-+    char *tmp_file_path;
-+    pa_hashmap *tables; /* table name -> pa_inidb_table */
-+    pa_time_event *time_event;
-+    bool failed;
-+    void *userdata;
-+};
-+
-+struct pa_inidb_table {
-+    pa_inidb *db;
-+    char *name;
-+    pa_hashmap *columns; /* column name -> column */
-+    pa_hashmap *rows; /* row id -> pa_inidb_row */
-+    pa_inidb_get_object_cb_t get_object;
-+};
-+
-+struct column {
-+    char *name;
-+    pa_inidb_parse_cb_t parse;
-+};
-+
-+struct pa_inidb_row {
-+    char *id;
-+    char *header;
-+    pa_hashmap *cells; /* column name -> cell */
-+};
-+
-+struct pa_inidb_cell {
-+    pa_inidb *db;
-+    struct column *column;
-+    char *value;
-+    char *assignment;
-+};
-+
-+static void save(pa_inidb *db);
-+
-+static pa_inidb_table *table_new(pa_inidb *db, const char *name, pa_inidb_get_object_cb_t get_object_cb);
-+static void table_free(pa_inidb_table *table);
-+static pa_inidb_row *table_add_row_internal(pa_inidb_table *table, const char *row_id);
-+
-+static struct column *column_new(const char *name, pa_inidb_parse_cb_t parse_cb);
-+static void column_free(struct column *column);
-+
-+static pa_inidb_row *row_new(pa_inidb_table *table, const char *id);
-+static void row_free(pa_inidb_row *row);
-+
-+static pa_inidb_cell *cell_new(pa_inidb *db, struct column *column);
-+static void cell_free(pa_inidb_cell *cell);
-+static void cell_set_value_internal(pa_inidb_cell *cell, const char *value);
-+
-+static int parse_assignment(pa_config_parser_state *state) {
-+    pa_inidb *db;
-+    const char *end_of_table_name;
-+    size_t table_name_len;
-+    char *table_name;
-+    pa_inidb_table *table;
-+    const char *row_id;
-+    pa_inidb_row *row;
-+    int r;
-+    void *object;
-+    struct column *column;
-+    pa_inidb_cell *cell;
-+
-+    pa_assert(state);
-+
-+    db = state->userdata;
-+
-+    /* FIXME: pa_config_parser should be improved so that it could parse the
-+     * table name and row id for us in the section header. */
-+    end_of_table_name = strchr(state->section, ' ');
-+    if (!end_of_table_name) {
-+        pa_log("[%s:%u] Failed to parse table name and row id in section \"%s\"", state->filename, state->lineno,
-+               state->section);
-+        return -PA_ERR_INVALID;
-+    }
-+
-+    table_name_len = end_of_table_name - state->section;
-+    table_name = pa_xstrndup(state->section, table_name_len);
-+    table = pa_hashmap_get(db->tables, table_name);
-+    if (!table)
-+        pa_log("[%s:%u] Unknown table name: \"%s\"", state->filename, state->lineno, table_name);
-+    pa_xfree(table_name);
-+    if (!table)
-+        return -PA_ERR_INVALID;
-+
-+    row_id = end_of_table_name + 1;
-+    if (!pa_namereg_is_valid_name(row_id)) {
-+        pa_log("[%s:%u] Invalid row id: \"%s\"", state->filename, state->lineno, row_id);
-+        return -PA_ERR_INVALID;
-+    }
-+
-+    /* This is not strictly necessary, but we do this to avoid saving the
-+     * database when there is no actual change. Without this, the get_object()
-+     * callback would cause redundant saving whenever creating new objects. */
-+    if (!(row = pa_hashmap_get(table->rows, row_id)))
-+        row = table_add_row_internal(table, row_id);
-+
-+    r = table->get_object(db, row_id, &object);
-+    if (r < 0) {
-+        pa_log("[%s:%u] Failed to create object %s.", state->filename, state->lineno, row_id);
-+        return r;
-+    }
-+
-+    column = pa_hashmap_get(table->columns, state->lvalue);
-+    if (!column) {
-+        pa_log("[%s:%u] Unknown column name: \"%s\"", state->filename, state->lineno, state->lvalue);
-+        return -PA_ERR_INVALID;
-+    }
-+
-+    /* This is not strictly necessary, but we do this to avoid saving the
-+     * database when there is no actual change. Without this, the parse()
-+     * callback would cause redundant saving whenever setting the cell value
-+     * for the first time. */
-+    cell = pa_hashmap_get(row->cells, column->name);
-+    cell_set_value_internal(cell, state->rvalue);
-+
-+    r = column->parse(db, state->rvalue, object);
-+    if (r < 0) {
-+        pa_log("[%s:%u] Failed to parse %s value \"%s\".", state->filename, state->lineno, column->name, state->rvalue);
-+        return r;
-+    }
-+
-+    return 0;
-+}
-+
-+pa_inidb *pa_inidb_new(pa_core *core, const char *name, void *userdata) {
-+    pa_inidb *db;
-+    int r;
-+
-+    pa_assert(core);
-+    pa_assert(name);
-+
-+    db = pa_xnew0(pa_inidb, 1);
-+    db->core = core;
-+    db->name = pa_xstrdup(name);
-+
-+    r = pa_append_to_config_home_dir(name, true, &db->file_path);
-+    if (r < 0) {
-+        pa_log("Failed to find the file location for database \"%s\". The database will start empty, and updates will not be "
-+               "saved on disk.", name);
-+        db->failed = true;
-+    }
-+
-+    if (db->file_path)
-+        db->tmp_file_path = pa_sprintf_malloc("%s.tmp", db->file_path);
-+
-+    db->tables = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
-+                                     (pa_free_cb_t) table_free);
-+    db->userdata = userdata;
-+
-+    return db;
-+}
-+
-+void pa_inidb_free(pa_inidb *db) {
-+    pa_assert(db);
-+
-+    if (db->time_event) {
-+        db->core->mainloop->time_free(db->time_event);
-+        save(db);
-+    }
-+
-+    if (db->tables)
-+        pa_hashmap_free(db->tables);
-+
-+    pa_xfree(db->tmp_file_path);
-+    pa_xfree(db->file_path);
-+    pa_xfree(db->name);
-+    pa_xfree(db);
-+}
-+
-+void *pa_inidb_get_userdata(pa_inidb *db) {
-+    pa_assert(db);
-+
-+    return db->userdata;
-+}
-+
-+pa_inidb_table *pa_inidb_add_table(pa_inidb *db, const char *name, pa_inidb_get_object_cb_t get_object_cb) {
-+    pa_inidb_table *table;
-+
-+    pa_assert(db);
-+    pa_assert(name);
-+    pa_assert(get_object_cb);
-+
-+    table = table_new(db, name, get_object_cb);
-+    pa_assert_se(pa_hashmap_put(db->tables, table->name, table) >= 0);
-+
-+    return table;
-+}
-+
-+void pa_inidb_load(pa_inidb *db) {
-+    unsigned n_config_items;
-+    pa_inidb_table *table;
-+    void *state;
-+    pa_config_item *config_items;
-+    unsigned i;
-+
-+    pa_assert(db);
-+
-+    if (db->failed)
-+        return;
-+
-+    n_config_items = 0;
-+    PA_HASHMAP_FOREACH(table, db->tables, state)
-+        n_config_items += pa_hashmap_size(table->columns);
-+
-+    config_items = pa_xnew0(pa_config_item, n_config_items + 1);
-+
-+    i = 0;
-+    PA_HASHMAP_FOREACH(table, db->tables, state) {
-+        struct column *column;
-+        void *state2;
-+
-+        PA_HASHMAP_FOREACH(column, table->columns, state2) {
-+            config_items[i].lvalue = column->name;
-+            config_items[i].parse = parse_assignment;
-+            i++;
-+        }
-+    }
-+
-+    pa_config_parse(db->file_path, NULL, config_items, NULL, db);
-+    pa_xfree(config_items);
-+}
-+
-+static void save(pa_inidb *db) {
-+    FILE *f;
-+    pa_inidb_table *table;
-+    void *state;
-+    int r;
-+
-+    pa_assert(db);
-+
-+    if (db->failed)
-+        return;
-+
-+    f = pa_fopen_cloexec(db->tmp_file_path, "w");
-+    if (!f) {
-+        pa_log("pa_fopen_cloexec() failed: %s", pa_cstrerror(errno));
-+        goto fail;
-+    }
-+
-+    PA_HASHMAP_FOREACH(table, db->tables, state) {
-+        pa_inidb_row *row;
-+        void *state2;
-+
-+        PA_HASHMAP_FOREACH(row, table->rows, state2) {
-+            size_t len;
-+            size_t items_written;
-+            pa_inidb_cell *cell;
-+            void *state3;
-+
-+            len = strlen(row->header);
-+            items_written = fwrite(row->header, len, 1, f);
-+
-+            if (items_written != 1) {
-+                pa_log("fwrite() failed: %s", pa_cstrerror(errno));
-+                goto fail;
-+            }
-+
-+            PA_HASHMAP_FOREACH(cell, row->cells, state3) {
-+                if (!cell->assignment)
-+                    continue;
-+
-+                len = strlen(cell->assignment);
-+                items_written = fwrite(cell->assignment, len, 1, f);
-+
-+                if (items_written != 1) {
-+                    pa_log("fwrite() failed: %s", pa_cstrerror(errno));
-+                    goto fail;
-+                }
-+            }
-+
-+            items_written = fwrite("\n", 1, 1, f);
-+
-+            if (items_written != 1) {
-+                pa_log("fwrite() failed: %s", pa_cstrerror(errno));
-+                goto fail;
-+            }
-+        }
-+    }
-+
-+    r = fclose(f);
-+    if (r < 0) {
-+        pa_log("fclose() failed: %s", pa_cstrerror(errno));
-+        goto fail;
-+    }
-+
-+    r = rename(db->tmp_file_path, db->file_path);
-+    if (r < 0) {
-+        pa_log("rename() failed: %s", pa_cstrerror(errno));
-+        goto fail;
-+    }
-+
-+    pa_log_debug("Database \"%s\" saved.", db->name);
-+
-+    return;
-+
-+fail:
-+    if (f)
-+        fclose(f);
-+
-+    db->failed = true;
-+    pa_log("Saving database \"%s\" failed, current and future database changes will not be written to the disk.", db->name);
-+}
-+
-+static pa_inidb_table *table_new(pa_inidb *db, const char *name, pa_inidb_get_object_cb_t get_object_cb) {
-+    pa_inidb_table *table;
-+
-+    pa_assert(db);
-+    pa_assert(name);
-+    pa_assert(get_object_cb);
-+
-+    table = pa_xnew0(pa_inidb_table, 1);
-+    table->db = db;
-+    table->name = pa_xstrdup(name);
-+    table->columns = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
-+                                         (pa_free_cb_t) column_free);
-+    table->rows = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
-+                                      (pa_free_cb_t) row_free);
-+    table->get_object = get_object_cb;
-+
-+    return table;
-+}
-+
-+static void table_free(pa_inidb_table *table) {
-+    pa_assert(table);
-+
-+    if (table->rows)
-+        pa_hashmap_free(table->rows);
-+
-+    if (table->columns)
-+        pa_hashmap_free(table->columns);
-+
-+    pa_xfree(table->name);
-+    pa_xfree(table);
-+}
-+
-+void pa_inidb_table_add_column(pa_inidb_table *table, const char *name, pa_inidb_parse_cb_t parse_cb) {
-+    struct column *column;
-+
-+    pa_assert(table);
-+    pa_assert(name);
-+    pa_assert(parse_cb);
-+
-+    column = column_new(name, parse_cb);
-+    pa_assert_se(pa_hashmap_put(table->columns, column->name, column) >= 0);
-+}
-+
-+static pa_inidb_row *table_add_row_internal(pa_inidb_table *table, const char *row_id) {
-+    pa_inidb_row *row;
-+
-+    pa_assert(table);
-+    pa_assert(row_id);
-+
-+    row = row_new(table, row_id);
-+    pa_assert_se(pa_hashmap_put(table->rows, row->id, row) >= 0);
-+
-+    return row;
-+}
-+
-+static void time_cb(pa_mainloop_api *api, pa_time_event *event, const struct timeval *tv, void *userdata) {
-+    pa_inidb *db = userdata;
-+
-+    pa_assert(api);
-+    pa_assert(db);
-+
-+    api->time_free(event);
-+    db->time_event = NULL;
-+
-+    save(db);
-+}
-+
-+static void trigger_save(pa_inidb *db) {
-+    struct timeval tv;
-+
-+    pa_assert(db);
-+
-+    if (db->time_event)
-+        return;
-+
-+    pa_timeval_rtstore(&tv, pa_rtclock_now() + SAVE_INTERVAL_USEC, true);
-+    db->time_event = db->core->mainloop->time_new(db->core->mainloop, &tv, time_cb, db);
-+}
-+
-+pa_inidb_row *pa_inidb_table_add_row(pa_inidb_table *table, const char *row_id) {
-+    pa_inidb_row *row;
-+
-+    pa_assert(table);
-+    pa_assert(row_id);
-+
-+    row = pa_hashmap_get(table->rows, row_id);
-+    if (row)
-+        return row;
-+
-+    row = table_add_row_internal(table, row_id);
-+    trigger_save(table->db);
-+
-+    return row;
-+}
-+
-+static struct column *column_new(const char *name, pa_inidb_parse_cb_t parse_cb) {
-+    struct column *column;
-+
-+    pa_assert(name);
-+    pa_assert(parse_cb);
-+
-+    column = pa_xnew(struct column, 1);
-+    column->name = pa_xstrdup(name);
-+    column->parse = parse_cb;
-+
-+    return column;
-+}
-+
-+static void column_free(struct column *column) {
-+    pa_assert(column);
-+
-+    pa_xfree(column->name);
-+    pa_xfree(column);
-+}
-+
-+static pa_inidb_row *row_new(pa_inidb_table *table, const char *id) {
-+    pa_inidb_row *row;
-+    struct column *column;
-+    void *state;
-+
-+    pa_assert(table);
-+    pa_assert(id);
-+
-+    row = pa_xnew0(pa_inidb_row, 1);
-+    row->id = pa_xstrdup(id);
-+    row->header = pa_sprintf_malloc("[%s %s]\n", table->name, id);
-+    row->cells = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
-+                                     (pa_free_cb_t) cell_free);
-+
-+    PA_HASHMAP_FOREACH(column, table->columns, state) {
-+        pa_inidb_cell *cell;
-+
-+        cell = cell_new(table->db, column);
-+        pa_hashmap_put(row->cells, cell->column->name, cell);
-+    }
-+
-+    return row;
-+}
-+
-+static void row_free(pa_inidb_row *row) {
-+    pa_assert(row);
-+
-+    pa_xfree(row->header);
-+    pa_xfree(row->id);
-+    pa_xfree(row);
-+}
-+
-+pa_inidb_cell *pa_inidb_row_get_cell(pa_inidb_row *row, const char *column_name) {
-+    pa_inidb_cell *cell;
-+
-+    pa_assert(row);
-+    pa_assert(column_name);
-+
-+    pa_assert_se(cell = pa_hashmap_get(row->cells, column_name));
-+
-+    return cell;
-+}
-+
-+static pa_inidb_cell *cell_new(pa_inidb *db, struct column *column) {
-+    pa_inidb_cell *cell;
-+
-+    pa_assert(db);
-+    pa_assert(column);
-+
-+    cell = pa_xnew0(pa_inidb_cell, 1);
-+    cell->db = db;
-+    cell->column = column;
-+
-+    return cell;
-+}
-+
-+static void cell_free(pa_inidb_cell *cell) {
-+    pa_assert(cell);
-+
-+    pa_xfree(cell->assignment);
-+    pa_xfree(cell->value);
-+    pa_xfree(cell);
-+}
-+
-+static void cell_set_value_internal(pa_inidb_cell *cell, const char *value) {
-+    pa_assert(cell);
-+    pa_assert(value);
-+
-+    pa_xfree(cell->value);
-+    cell->value = pa_xstrdup(value);
-+
-+    pa_xfree(cell->assignment);
-+    if (value)
-+        cell->assignment = pa_sprintf_malloc("%s = %s\n", cell->column->name, value);
-+    else
-+        cell->assignment = NULL;
-+}
-+
-+void pa_inidb_cell_set_value(pa_inidb_cell *cell, const char *value) {
-+    pa_assert(cell);
-+
-+    if (pa_safe_streq(value, cell->value))
-+        return;
-+
-+    cell_set_value_internal(cell, value);
-+    trigger_save(cell->db);
-+}
-diff --git a/src/modules/volume-api/inidb.h b/src/modules/volume-api/inidb.h
-new file mode 100644
-index 0000000..ded73ba
---- /dev/null
-+++ b/src/modules/volume-api/inidb.h
-@@ -0,0 +1,54 @@
-+#ifndef fooinidbhfoo
-+#define fooinidbhfoo
-+
-+/***
-+  This file is part of PulseAudio.
-+
-+  Copyright 2014 Intel Corporation
-+
-+  PulseAudio is free software; you can redistribute it and/or modify
-+  it under the terms of the GNU Lesser General Public License as published
-+  by the Free Software Foundation; either version 2.1 of the License,
-+  or (at your option) any later version.
-+
-+  PulseAudio is distributed in the hope that it will be useful, but
-+  WITHOUT ANY WARRANTY; without even the implied warranty of
-+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+  General Public License for more details.
-+
-+  You should have received a copy of the GNU Lesser General Public License
-+  along with PulseAudio; if not, write to the Free Software
-+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-+  USA.
-+***/
-+
-+#include <pulsecore/core.h>
-+
-+typedef struct pa_inidb pa_inidb;
-+typedef struct pa_inidb_cell pa_inidb_cell;
-+typedef struct pa_inidb_row pa_inidb_row;
-+typedef struct pa_inidb_table pa_inidb_table;
-+
-+/* If there's no object with the given name, the implementation is expected to
-+ * create a new object (or at least try to). */
-+typedef int (*pa_inidb_get_object_cb_t)(pa_inidb *db, const char *name, void **_r);
-+
-+/* The implementation is expected to parse the value, and set the parsed value
-+ * on the object. */
-+typedef int (*pa_inidb_parse_cb_t)(pa_inidb *db, const char *value, void *object);
-+
-+pa_inidb *pa_inidb_new(pa_core *core, const char *name, void *userdata);
-+void pa_inidb_free(pa_inidb *db);
-+
-+void *pa_inidb_get_userdata(pa_inidb *db);
-+pa_inidb_table *pa_inidb_add_table(pa_inidb *db, const char *name, pa_inidb_get_object_cb_t get_object_cb);
-+void pa_inidb_load(pa_inidb *db);
-+
-+void pa_inidb_table_add_column(pa_inidb_table *table, const char *name, pa_inidb_parse_cb_t parse_cb);
-+pa_inidb_row *pa_inidb_table_add_row(pa_inidb_table *table, const char *row_id);
-+
-+pa_inidb_cell *pa_inidb_row_get_cell(pa_inidb_row *row, const char *column_name);
-+
-+void pa_inidb_cell_set_value(pa_inidb_cell *cell, const char *value);
-+
-+#endif
-diff --git a/src/modules/volume-api/module-volume-api.c b/src/modules/volume-api/module-volume-api.c
-index 845ac09..7b112f6 100644
---- a/src/modules/volume-api/module-volume-api.c
-+++ b/src/modules/volume-api/module-volume-api.c
-@@ -51,6 +51,7 @@ struct userdata {
-     pa_hook_slot *volume_control_unlink_slot;
-     pa_hook_slot *volume_control_description_changed_slot;
-     pa_hook_slot *volume_control_volume_changed_slot;
-+    pa_hook_slot *volume_control_convertible_to_db_changed_slot;
-     pa_hook_slot *mute_control_put_slot;
-     pa_hook_slot *mute_control_unlink_slot;
-     pa_hook_slot *mute_control_description_changed_slot;
-@@ -63,10 +64,13 @@ struct userdata {
-     pa_hook_slot *stream_put_slot;
-     pa_hook_slot *stream_unlink_slot;
-     pa_hook_slot *stream_description_changed_slot;
-+    pa_hook_slot *stream_proplist_changed_slot;
-     pa_hook_slot *stream_volume_control_changed_slot;
-+    pa_hook_slot *stream_relative_volume_control_changed_slot;
-     pa_hook_slot *stream_mute_control_changed_slot;
-     pa_hook_slot *audio_group_put_slot;
-     pa_hook_slot *audio_group_unlink_slot;
-+    pa_hook_slot *audio_group_description_changed_slot;
-     pa_hook_slot *audio_group_volume_control_changed_slot;
-     pa_hook_slot *audio_group_mute_control_changed_slot;
-     pa_hook_slot *main_output_volume_control_changed_slot;
-@@ -1247,6 +1251,9 @@ int pa__init(pa_module *module) {
-     u->volume_control_volume_changed_slot =
-             pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_VOLUME_CHANGED],
-                             PA_HOOK_NORMAL, volume_control_event_cb, u);
-+    u->volume_control_convertible_to_db_changed_slot =
-+            pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_CONVERTIBLE_TO_DB_CHANGED], PA_HOOK_NORMAL,
-+                            volume_control_event_cb, u);
-     u->mute_control_put_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_PUT],
-                                                PA_HOOK_NORMAL, mute_control_put_cb, u);
-     u->mute_control_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK],
-@@ -1277,9 +1284,14 @@ int pa__init(pa_module *module) {
-     u->stream_description_changed_slot =
-             pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_DESCRIPTION_CHANGED], PA_HOOK_NORMAL,
-                             stream_event_cb, u);
-+    u->stream_proplist_changed_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_PROPLIST_CHANGED],
-+                                                      PA_HOOK_NORMAL, stream_event_cb, u);
-     u->stream_volume_control_changed_slot =
-             pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_VOLUME_CONTROL_CHANGED],
-                             PA_HOOK_NORMAL, stream_event_cb, u);
-+    u->stream_relative_volume_control_changed_slot =
-+            pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_RELATIVE_VOLUME_CONTROL_CHANGED],
-+                            PA_HOOK_NORMAL, stream_event_cb, u);
-     u->stream_mute_control_changed_slot =
-             pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_MUTE_CONTROL_CHANGED], PA_HOOK_NORMAL,
-                             stream_event_cb, u);
-@@ -1287,6 +1299,9 @@ int pa__init(pa_module *module) {
-                                               PA_HOOK_NORMAL, audio_group_put_cb, u);
-     u->audio_group_unlink_slot = pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK],
-                                                  PA_HOOK_NORMAL, audio_group_unlink_cb, u);
-+    u->audio_group_description_changed_slot =
-+            pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_DESCRIPTION_CHANGED], PA_HOOK_NORMAL,
-+                            audio_group_event_cb, u);
-     u->audio_group_volume_control_changed_slot =
-             pa_hook_connect(&u->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_VOLUME_CONTROL_CHANGED],
-                             PA_HOOK_NORMAL, audio_group_event_cb, u);
-@@ -1352,6 +1367,9 @@ void pa__done(pa_module *module) {
-     if (u->audio_group_volume_control_changed_slot)
-         pa_hook_slot_free(u->audio_group_volume_control_changed_slot);
-+    if (u->audio_group_description_changed_slot)
-+        pa_hook_slot_free(u->audio_group_description_changed_slot);
-+
-     if (u->audio_group_unlink_slot)
-         pa_hook_slot_free(u->audio_group_unlink_slot);
-@@ -1361,9 +1379,15 @@ void pa__done(pa_module *module) {
-     if (u->stream_mute_control_changed_slot)
-         pa_hook_slot_free(u->stream_mute_control_changed_slot);
-+    if (u->stream_relative_volume_control_changed_slot)
-+        pa_hook_slot_free(u->stream_relative_volume_control_changed_slot);
-+
-     if (u->stream_volume_control_changed_slot)
-         pa_hook_slot_free(u->stream_volume_control_changed_slot);
-+    if (u->stream_proplist_changed_slot)
-+        pa_hook_slot_free(u->stream_proplist_changed_slot);
-+
-     if (u->stream_description_changed_slot)
-         pa_hook_slot_free(u->stream_description_changed_slot);
-@@ -1400,6 +1424,9 @@ void pa__done(pa_module *module) {
-     if (u->mute_control_put_slot)
-         pa_hook_slot_free(u->mute_control_put_slot);
-+    if (u->volume_control_convertible_to_db_changed_slot)
-+        pa_hook_slot_free(u->volume_control_convertible_to_db_changed_slot);
-+
-     if (u->volume_control_volume_changed_slot)
-         pa_hook_slot_free(u->volume_control_volume_changed_slot);
-diff --git a/src/modules/volume-api/mute-control.c b/src/modules/volume-api/mute-control.c
-index adc008e..1b2f276 100644
---- a/src/modules/volume-api/mute-control.c
-+++ b/src/modules/volume-api/mute-control.c
-@@ -31,52 +31,73 @@
- #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;
-+int pa_mute_control_new(pa_volume_api *api, const char *name, bool persistent, pa_mute_control **_r) {
-+    pa_mute_control *control = NULL;
-+    int r;
-     pa_assert(api);
-     pa_assert(name);
--    pa_assert(description);
-+    pa_assert(_r);
-     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);
-+
-+    r = pa_volume_api_register_name(api, name, false, &control->name);
-+    if (r < 0)
-+        goto fail;
-+
-+    control->description = pa_xstrdup(control->name);
-     control->proplist = pa_proplist_new();
-+    control->present = !persistent;
-+    control->persistent = persistent;
-+    control->purpose = PA_MUTE_CONTROL_PURPOSE_OTHER;
-     control->devices = pa_hashmap_new(NULL, NULL);
-     control->default_for_devices = pa_hashmap_new(NULL, NULL);
--    control->streams = pa_hashmap_new(NULL, NULL);
--    control->audio_groups = pa_hashmap_new(NULL, NULL);
--    return control;
-+    if (persistent) {
-+        pa_inidb_row *row;
-+
-+        row = pa_inidb_table_add_row(api->control_db.mute_controls, control->name);
-+        control->db_cells.description = pa_inidb_row_get_cell(row, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_DESCRIPTION);
-+        control->db_cells.mute = pa_inidb_row_get_cell(row, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_MUTE);
-+    }
-+
-+    *_r = control;
-+    return 0;
-+
-+fail:
-+    if (control)
-+        pa_mute_control_free(control);
-+
-+    return r;
- }
--void pa_mute_control_put(pa_mute_control *control, bool initial_mute, bool initial_mute_is_set,
--                         pa_mute_control_set_initial_mute_cb_t set_initial_mute_cb) {
-+void pa_mute_control_put(pa_mute_control *control) {
-     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);
-+    pa_assert(control->set_mute || !control->present);
--    if (initial_mute_is_set)
--        control->mute = initial_mute;
--    else
--        control->mute = false;
-+    pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_IMPLEMENTATION_INITIALIZED], control);
-+    pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_SET_INITIAL_MUTE], control);
--    if (set_initial_mute_cb)
--        set_initial_mute_cb(control);
-+    if (control->set_mute) {
-+        control->set_mute_in_progress = true;
-+        control->set_mute(control, control->mute);
-+        control->set_mute_in_progress = false;
-+    }
-     pa_volume_api_add_mute_control(control->volume_api, control);
--
-     control->linked = true;
-     pa_log_debug("Created mute control #%u.", control->index);
-     pa_log_debug("    Name: %s", control->name);
-     pa_log_debug("    Description: %s", control->description);
-     pa_log_debug("    Mute: %s", pa_yes_no(control->mute));
-+    pa_log_debug("    Present: %s", pa_yes_no(control->present));
-+    pa_log_debug("    Persistent: %s", pa_yes_no(control->persistent));
-     pa_log_debug("    Properties:");
-     while ((prop_key = pa_proplist_iterate(control->proplist, &state)))
-@@ -86,9 +107,7 @@ void pa_mute_control_put(pa_mute_control *control, bool initial_mute, bool initi
- }
- void pa_mute_control_unlink(pa_mute_control *control) {
--    pa_audio_group *group;
-     pa_device *device;
--    pas_stream *stream;
-     pa_assert(control);
-@@ -102,15 +121,9 @@ void pa_mute_control_unlink(pa_mute_control *control) {
-     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);
--    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);
-+    pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK], control);
-     while ((device = pa_hashmap_first(control->default_for_devices)))
-         pa_device_set_default_mute_control(device, NULL);
-@@ -133,19 +146,10 @@ void pa_mute_control_unlink(pa_mute_control *control) {
- void pa_mute_control_free(pa_mute_control *control) {
-     pa_assert(control);
--    if (!control->unlinked)
-+    /* unlink() expects name to be set. */
-+    if (!control->unlinked && control->name)
-         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);
-@@ -167,86 +171,137 @@ void pa_mute_control_free(pa_mute_control *control) {
-     pa_xfree(control);
- }
--void pa_mute_control_set_owner_audio_group(pa_mute_control *control, pa_audio_group *group) {
-+void pa_mute_control_set_purpose(pa_mute_control *control, pa_mute_control_purpose_t purpose, void *owner) {
-     pa_assert(control);
--    pa_assert(group);
-+    pa_assert(!control->linked);
--    control->owner_audio_group = group;
-+    control->purpose = purpose;
-+    control->owner = owner;
- }
--static void set_mute_internal(pa_mute_control *control, bool mute) {
--    bool old_mute;
--
-+int pa_mute_control_acquire_for_audio_group(pa_mute_control *control, pa_audio_group *group,
-+                                            pa_mute_control_set_mute_cb_t set_mute_cb, void *userdata) {
-     pa_assert(control);
-+    pa_assert(group);
-+    pa_assert(set_mute_cb);
--    old_mute = control->mute;
-+    if (control->present) {
-+        pa_log("Can't acquire mute control %s, it's already present.", control->name);
-+        return -PA_ERR_BUSY;
-+    }
--    if (mute == old_mute)
--        return;
-+    control->owner_audio_group = group;
-+    control->set_mute = set_mute_cb;
-+    control->userdata = userdata;
--    control->mute = mute;
-+    control->set_mute_in_progress = true;
-+    control->set_mute(control, control->mute);
-+    control->set_mute_in_progress = false;
-+
-+    control->present = true;
-     if (!control->linked || control->unlinked)
--        return;
-+        return 0;
--    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_log_debug("Mute control %s became present.", control->name);
--    pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_MUTE_CHANGED], control);
-+    return 0;
- }
--int pa_mute_control_set_mute(pa_mute_control *control, bool mute) {
--    int r;
--
-+void pa_mute_control_release(pa_mute_control *control) {
-     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 (!control->present)
-+        return;
--    if (mute == control->mute)
--        return 0;
-+    control->present = false;
--    control->set_mute_in_progress = true;
--    r = control->set_mute(control, mute);
--    control->set_mute_in_progress = false;
-+    control->userdata = NULL;
-+    control->set_mute = NULL;
-+    control->owner_audio_group = NULL;
--    if (r >= 0)
--        set_mute_internal(control, mute);
-+    if (!control->linked || control->unlinked)
-+        return;
--    return r;
-+    pa_log_debug("Mute control %s became not present.", control->name);
- }
--void pa_mute_control_description_changed(pa_mute_control *control, const char *new_description) {
-+void pa_mute_control_set_description(pa_mute_control *control, const char *description) {
-     char *old_description;
-     pa_assert(control);
--    pa_assert(new_description);
-+    pa_assert(description);
-     old_description = control->description;
--    if (pa_streq(new_description, old_description))
-+    if (pa_streq(description, old_description))
-+        return;
-+
-+    control->description = pa_xstrdup(description);
-+
-+    if (control->persistent)
-+        pa_inidb_cell_set_value(control->db_cells.description, description);
-+
-+    if (!control->linked || control->unlinked) {
-+        pa_xfree(old_description);
-         return;
-+    }
--    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);
-+                 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) {
-+static void set_mute_internal(pa_mute_control *control, bool mute) {
-+    bool old_mute;
-+
-     pa_assert(control);
--    if (!control->linked)
-+    old_mute = control->mute;
-+
-+    if (mute == old_mute)
-         return;
--    if (control->set_mute_in_progress)
-+    control->mute = mute;
-+
-+    if (control->persistent)
-+        pa_inidb_cell_set_value(control->db_cells.mute, pa_boolean_to_string(mute));
-+
-+    if (!control->linked || control->unlinked)
-         return;
--    set_mute_internal(control, new_mute);
-+    pa_log_debug("The mute of mute control %s changed from %s to %s.", control->name, pa_boolean_to_string(old_mute),
-+                 pa_boolean_to_string(control->mute));
-+
-+    pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_MUTE_CHANGED], control);
-+}
-+
-+int pa_mute_control_set_mute(pa_mute_control *control, bool mute) {
-+    int r;
-+
-+    pa_assert(control);
-+
-+    if (control->set_mute_in_progress)
-+        return 0;
-+
-+    if (mute == control->mute)
-+        return 0;
-+
-+    if (control->linked && control->present) {
-+        control->set_mute_in_progress = true;
-+        r = control->set_mute(control, mute);
-+        control->set_mute_in_progress = false;
-+
-+        if (r < 0) {
-+            pa_log("Setting the mute of mute control %s failed.", control->name);
-+            return r;
-+        }
-+    }
-+
-+    set_mute_internal(control, mute);
-+
-+    return 0;
- }
- void pa_mute_control_add_device(pa_mute_control *control, pa_device *device) {
-@@ -276,31 +331,3 @@ void pa_mute_control_remove_default_for_device(pa_mute_control *control, pa_devi
-     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
-index 1f70a43..40f8a9c 100644
---- a/src/modules/volume-api/mute-control.h
-+++ b/src/modules/volume-api/mute-control.h
-@@ -22,10 +22,18 @@
-   USA.
- ***/
-+#include <modules/volume-api/inidb.h>
- #include <modules/volume-api/volume-api.h>
- typedef struct pa_mute_control pa_mute_control;
-+typedef enum {
-+    PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE,
-+    PA_MUTE_CONTROL_PURPOSE_OTHER,
-+} pa_mute_control_purpose_t;
-+
-+typedef int (*pa_mute_control_set_mute_cb_t)(pa_mute_control *control, bool mute);
-+
- struct pa_mute_control {
-     pa_volume_api *volume_api;
-     uint32_t index;
-@@ -33,6 +41,14 @@ struct pa_mute_control {
-     char *description;
-     pa_proplist *proplist;
-     bool mute;
-+    bool present;
-+    bool persistent;
-+
-+    pa_mute_control_purpose_t purpose;
-+    union {
-+        pas_stream *owner_stream;
-+        void *owner;
-+    };
-     /* If this mute control is the "own mute control" of an audio group, this
-      * is set to point to that group, otherwise this is NULL. */
-@@ -40,50 +56,43 @@ struct pa_mute_control {
-     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) */
-+
-+    struct {
-+        pa_inidb_cell *description;
-+        pa_inidb_cell *mute;
-+    } db_cells;
-     bool linked;
-     bool unlinked;
-     bool set_mute_in_progress;
-     /* Called from pa_mute_control_set_mute(). The implementation is expected
--     * to return a negative error code on failure. May be NULL, if the mute
--     * control is read-only. */
--    int (*set_mute)(pa_mute_control *control, bool mute);
-+     * to return a negative error code on failure. */
-+    pa_mute_control_set_mute_cb_t set_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);
--
-+int pa_mute_control_new(pa_volume_api *api, const char *name, bool persistent, pa_mute_control **_r);
-+void pa_mute_control_put(pa_mute_control *control);
- void pa_mute_control_unlink(pa_mute_control *control);
- void pa_mute_control_free(pa_mute_control *control);
--/* Called by 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, before pa_mute_control_put(). */
-+void pa_mute_control_set_purpose(pa_mute_control *control, pa_mute_control_purpose_t purpose, void *owner);
- /* Called by the mute control implementation. */
--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);
-+int pa_mute_control_acquire_for_audio_group(pa_mute_control *control, pa_audio_group *group,
-+                                            pa_mute_control_set_mute_cb_t set_mute_cb, void *userdata);
-+
-+/* Called by the mute control implementation. This must only be called for
-+ * persistent controls; use pa_mute_control_free() for non-persistent
-+ * controls. */
-+void pa_mute_control_release(pa_mute_control *control);
-+
-+/* Called by anyone. */
-+void pa_mute_control_set_description(pa_mute_control *control, const char *description);
-+int pa_mute_control_set_mute(pa_mute_control *control, bool mute);
- /* Called from device.c only. */
- void pa_mute_control_add_device(pa_mute_control *control, pa_device *device);
-@@ -91,12 +100,4 @@ 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
-index e3531a8..1738d15 100644
---- a/src/modules/volume-api/sstream.c
-+++ b/src/modules/volume-api/sstream.c
-@@ -26,7 +26,6 @@
- #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>
-@@ -34,121 +33,43 @@
- #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;
-+int pas_stream_new(pa_volume_api *api, const char *name, pas_stream **_r) {
-+    pas_stream *stream = NULL;
-+    int r;
-     pa_assert(api);
-     pa_assert(name);
--    pa_assert(description);
-+    pa_assert(_r);
-     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;
-+    r = pa_volume_api_register_name(api, name, false, &stream->name);
-+    if (r < 0)
-+        goto fail;
--    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);
--    }
-+    stream->description = pa_xstrdup(stream->name);
-+    stream->direction = PA_DIRECTION_OUTPUT;
-+    stream->proplist = pa_proplist_new();
--    if (!stream->linked || stream->unlinked)
--        return;
-+    *_r = stream;
-+    return 0;
--    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)");
-+fail:
-+    if (stream)
-+        pas_stream_free(stream);
--    pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_MUTE_CONTROL_CHANGED], stream);
-+    return r;
- }
--void pas_stream_put(pas_stream *stream, pa_proplist *initial_properties) {
-+void pas_stream_put(pas_stream *stream) {
-     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);
-@@ -157,6 +78,10 @@ void pas_stream_put(pas_stream *stream, pa_proplist *initial_properties) {
-     pa_log_debug("    Direction: %s", pa_direction_to_string(stream->direction));
-     pa_log_debug("    Volume control: %s", stream->volume_control ? stream->volume_control->name : "(unset)");
-     pa_log_debug("    Mute control: %s", stream->mute_control ? stream->mute_control->name : "(unset)");
-+    pa_log_debug("    Audio group for volume: %s",
-+                 stream->audio_group_for_volume ? stream->audio_group_for_volume->name : "(unset)");
-+    pa_log_debug("    Audio group for mute: %s",
-+                 stream->audio_group_for_mute ? stream->audio_group_for_mute->name : "(unset)");
-     pa_log_debug("    Properties:");
-     while ((prop_key = pa_proplist_iterate(stream->proplist, &state)))
-@@ -178,22 +103,22 @@ void pas_stream_unlink(pas_stream *stream) {
-     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);
--    pa_volume_api_remove_stream(stream->volume_api, stream);
-+    pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_UNLINK], stream);
-     pas_stream_set_audio_group_for_mute(stream, NULL);
-     pas_stream_set_audio_group_for_volume(stream, NULL);
-     pas_stream_set_mute_control(stream, NULL);
-+    pas_stream_set_relative_volume_control(stream, NULL);
-     pas_stream_set_volume_control(stream, NULL);
--    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)
-+    /* unlink() expects name to be set. */
-+    if (!stream->unlinked && stream->name)
-         pas_stream_unlink(stream);
-     if (stream->proplist)
-@@ -207,160 +132,172 @@ void pas_stream_free(pas_stream *stream) {
-     pa_xfree(stream);
- }
--int pas_stream_set_have_own_volume_control(pas_stream *stream, bool have) {
-+void pas_stream_set_direction(pas_stream *stream, pa_direction_t direction) {
-     pa_assert(stream);
-+    pa_assert(!stream->linked);
--    if (have == stream->have_own_volume_control)
--        return 0;
-+    stream->direction = direction;
-+}
--    if (have) {
--        pa_assert(!stream->own_volume_control);
-+void pas_stream_set_description(pas_stream *stream, const char *description) {
-+    char *old_description;
-+
-+    pa_assert(stream);
-+    pa_assert(description);
--        if (!stream->create_own_volume_control) {
--            pa_log_debug("Stream %s doesn't support own volume control.", stream->name);
--            return -PA_ERR_NOTSUPPORTED;
--        }
-+    old_description = stream->description;
-+
-+    if (pa_streq(description, old_description))
-+        return;
--        stream->own_volume_control = stream->create_own_volume_control(stream);
--    } else {
--        stream->delete_own_volume_control(stream);
--        stream->own_volume_control = NULL;
-+    stream->description = pa_xstrdup(description);
-+
-+    if (!stream->linked || stream->unlinked) {
-+        pa_xfree(old_description);
-+        return;
-     }
--    stream->have_own_volume_control = have;
-+    pa_log_debug("Stream %s description changed from \"%s\" to \"%s\".", stream->name, old_description,
-+                 description);
-+    pa_xfree(old_description);
--    return 0;
-+    pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_DESCRIPTION_CHANGED], stream);
- }
--int pas_stream_set_have_own_mute_control(pas_stream *stream, bool have) {
-+void pas_stream_set_property(pas_stream *stream, const char *key, const char *value) {
-+    const char *old_value;
-+
-     pa_assert(stream);
-+    pa_assert(key);
--    if (have == stream->have_own_mute_control)
--        return 0;
-+    old_value = pa_proplist_gets(stream->proplist, key);
--    if (have) {
--        pa_assert(!stream->own_mute_control);
-+    if (pa_safe_streq(value, old_value))
-+        return;
--        if (!stream->create_own_mute_control) {
--            pa_log_debug("Stream %s doesn't support own mute control.", stream->name);
--            return -PA_ERR_NOTSUPPORTED;
--        }
-+    if (value)
-+        pa_proplist_sets(stream->proplist, key, value);
-+    else
-+        pa_proplist_unset(stream->proplist, key);
--        stream->own_mute_control = stream->create_own_mute_control(stream);
--    } else {
--        stream->delete_own_mute_control(stream);
--        stream->own_mute_control = NULL;
--    }
-+    if (!stream->linked || stream->unlinked)
-+        return;
--    stream->have_own_mute_control = have;
-+    pa_log_debug("Stream %s property \"%s\" changed from \"%s\" to \"%s\".", stream->name, key,
-+                 old_value ? old_value : "(unset)", value ? value : "(unset)");
--    return 0;
-+    pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_PROPLIST_CHANGED], stream);
- }
- void pas_stream_set_volume_control(pas_stream *stream, pa_volume_control *control) {
--    pa_assert(stream);
-+    pa_volume_control *old_control;
--    stream->use_default_volume_control = false;
-+    pa_assert(stream);
--    if (stream->volume_control_binding) {
--        pa_binding_free(stream->volume_control_binding);
--        stream->volume_control_binding = NULL;
--    }
-+    old_control = stream->volume_control;
--    set_volume_control_internal(stream, control);
--}
-+    if (control == old_control)
-+        return;
--void pas_stream_set_mute_control(pas_stream *stream, pa_mute_control *control) {
--    pa_assert(stream);
-+    stream->volume_control = control;
--    stream->use_default_mute_control = false;
-+    if (!stream->linked || stream->unlinked)
-+        return;
--    if (stream->mute_control_binding) {
--        pa_binding_free(stream->mute_control_binding);
--        stream->mute_control_binding = NULL;
--    }
-+    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)");
--    set_mute_control_internal(stream, control);
-+    pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_VOLUME_CONTROL_CHANGED], stream);
- }
--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,
--    };
-+void pas_stream_set_relative_volume_control(pas_stream *stream, pa_volume_control *control) {
-+    pa_volume_control *old_control;
-     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);
-+    old_control = stream->relative_volume_control;
--    stream->volume_control_binding = pa_binding_new(stream->volume_api, &owner_info, target_info);
--}
-+    if (control == old_control)
-+        return;
--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,
--    };
-+    stream->relative_volume_control = control;
--    pa_assert(stream);
--    pa_assert(target_info);
--
--    stream->use_default_mute_control = false;
-+    if (!stream->linked || stream->unlinked)
-+        return;
--    if (stream->mute_control_binding)
--        pa_binding_free(stream->mute_control_binding);
-+    pa_log_debug("The relative volume control of stream %s changed from %s to %s.", stream->name,
-+                 old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
--    stream->mute_control_binding = pa_binding_new(stream->volume_api, &owner_info, target_info);
-+    pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_RELATIVE_VOLUME_CONTROL_CHANGED], stream);
- }
--void pas_stream_description_changed(pas_stream *stream, const char *new_description) {
--    char *old_description;
-+void pas_stream_set_mute_control(pas_stream *stream, pa_mute_control *control) {
-+    pa_mute_control *old_control;
-     pa_assert(stream);
--    pa_assert(new_description);
--    old_description = stream->description;
-+    old_control = stream->mute_control;
--    if (pa_streq(new_description, old_description))
-+    if (control == old_control)
-         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);
-+    stream->mute_control = control;
-+
-+    if (!stream->linked || stream->unlinked)
-+        return;
-+
-+    pa_log_debug("The mute control of stream %s changed from %s to %s.", stream->name,
-+                 old_control ? old_control->name : "(unset)", control ? control->name : "(unset)");
-+
-+    pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_MUTE_CONTROL_CHANGED], stream);
- }
- void pas_stream_set_audio_group_for_volume(pas_stream *stream, pa_audio_group *group) {
-+    pa_audio_group *old_group;
-+
-     pa_assert(stream);
--    if (group == stream->audio_group_for_volume)
-+    old_group = stream->audio_group_for_volume;
-+
-+    if (group == old_group)
-         return;
--    if (stream->audio_group_for_volume)
--        pa_audio_group_remove_volume_stream(stream->audio_group_for_volume, stream);
-+    if (old_group)
-+        pa_audio_group_remove_volume_stream(old_group, stream);
-     stream->audio_group_for_volume = group;
-     if (group)
-         pa_audio_group_add_volume_stream(group, stream);
-+
-+    if (!stream->linked || stream->unlinked)
-+        return;
-+
-+    pa_log_debug("Stream %s audio group for volume changed from %s to %s.", stream->name,
-+                 old_group ? old_group->name : "(unset)", group ? group->name : "(unset)");
- }
- void pas_stream_set_audio_group_for_mute(pas_stream *stream, pa_audio_group *group) {
-+    pa_audio_group *old_group;
-+
-     pa_assert(stream);
--    if (group == stream->audio_group_for_mute)
-+    old_group = stream->audio_group_for_mute;
-+
-+    if (group == old_group)
-         return;
--    if (stream->audio_group_for_mute)
--        pa_audio_group_remove_mute_stream(stream->audio_group_for_mute, stream);
-+    if (old_group)
-+        pa_audio_group_remove_mute_stream(old_group, stream);
-     stream->audio_group_for_mute = group;
-     if (group)
-         pa_audio_group_add_mute_stream(group, stream);
-+
-+    if (!stream->linked || stream->unlinked)
-+        return;
-+
-+    pa_log_debug("Stream %s audio group for mute changed from %s to %s.", stream->name,
-+                 old_group ? old_group->name : "(unset)", group ? group->name : "(unset)");
- }
-diff --git a/src/modules/volume-api/sstream.h b/src/modules/volume-api/sstream.h
-index a65b34c..715bf2c 100644
---- a/src/modules/volume-api/sstream.h
-+++ b/src/modules/volume-api/sstream.h
-@@ -39,69 +39,33 @@ struct pas_stream {
-     pa_direction_t direction;
-     pa_proplist *proplist;
-     pa_volume_control *volume_control;
-+    pa_volume_control *relative_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);
-+int pas_stream_new(pa_volume_api *api, const char *name, pas_stream **_r);
-+void pas_stream_put(pas_stream *stream);
- void pas_stream_unlink(pas_stream *stream);
- void pas_stream_free(pas_stream *stream);
--/* Called by the stream implementation 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 the stream implementation, only during initialization. */
-+void pas_stream_set_direction(pas_stream *stream, pa_direction_t direction);
--/* Called by policy modules. */
-+/* Called by the stream implementation. */
-+void pas_stream_set_description(pas_stream *stream, const char *description);
-+void pas_stream_set_property(pas_stream *stream, const char *key, const char *value);
- void pas_stream_set_volume_control(pas_stream *stream, pa_volume_control *control);
-+void pas_stream_set_relative_volume_control(pas_stream *stream, pa_volume_control *control);
- void pas_stream_set_mute_control(pas_stream *stream, pa_mute_control *control);
--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. */
-+/* Called by anyone. */
- void pas_stream_set_audio_group_for_volume(pas_stream *stream, pa_audio_group *group);
- void pas_stream_set_audio_group_for_mute(pas_stream *stream, pa_audio_group *group);
-diff --git a/src/modules/volume-api/stream-creator.c b/src/modules/volume-api/stream-creator.c
-index f6ca7b3..0d9ea24 100644
---- a/src/modules/volume-api/stream-creator.c
-+++ b/src/modules/volume-api/stream-creator.c
-@@ -35,9 +35,9 @@
- 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_fixate_slot;
-     pa_hook_slot *sink_input_unlink_slot;
--    pa_hook_slot *source_output_put_slot;
-+    pa_hook_slot *source_output_fixate_slot;
-     pa_hook_slot *source_output_unlink_slot;
- };
-@@ -47,73 +47,61 @@ enum stream_type {
- };
- struct stream {
-+    pa_core *core;
-     pa_stream_creator *creator;
-     enum stream_type type;
-+    pa_sink_input_new_data *sink_input_new_data;
-     pa_sink_input *sink_input;
-+    pa_source_output_new_data *source_output_new_data;
-     pa_source_output *source_output;
-     pa_client *client;
-+    pa_volume_control *volume_control;
-+    pa_volume_control *relative_volume_control;
-+    pa_mute_control *mute_control;
-     pas_stream *stream;
--    bool unlinked;
--
-     pa_hook_slot *proplist_changed_slot;
--    pa_hook_slot *client_proplist_changed_slot;
-     pa_hook_slot *volume_changed_slot;
-+    pa_hook_slot *reference_ratio_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 void stream_free(struct stream *stream);
--static int volume_control_set_volume_cb(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance) {
-+static int volume_control_set_volume_cb(pa_volume_control *control, const pa_bvolume *original_volume,
-+                                        const pa_bvolume *remapped_volume, bool set_volume, bool set_balance) {
-     struct stream *stream;
-     pa_bvolume bvolume;
-     pa_cvolume cvolume;
-     pa_assert(control);
--    pa_assert(volume);
-+    pa_assert(original_volume);
-+    pa_assert(remapped_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;
--    }
-+    bvolume = control->volume;
-     if (set_volume)
--        bvolume.volume = volume->volume;
-+        bvolume.volume = remapped_volume->volume;
-     if (set_balance)
--        pa_bvolume_copy_balance(&bvolume, volume);
-+        pa_bvolume_copy_balance(&bvolume, remapped_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);
-+            if (stream->sink_input->state == PA_SINK_INPUT_INIT)
-+                pa_sink_input_new_data_set_volume(stream->sink_input_new_data, &cvolume, false);
-+            else
-+                pa_sink_input_set_volume(stream->sink_input, &cvolume, true, true);
-             break;
-         case STREAM_TYPE_SOURCE_OUTPUT:
--            pa_source_output_set_volume(stream->source_output, &cvolume, true, true);
-+            if (stream->source_output->state == PA_SOURCE_OUTPUT_INIT)
-+                pa_source_output_new_data_set_volume(stream->source_output_new_data, &cvolume, false);
-+            else
-+                pa_source_output_set_volume(stream->source_output, &cvolume, true, true);
-             break;
-     }
-@@ -129,6 +117,9 @@ static pa_hook_result_t sink_input_or_source_output_volume_changed_cb(void *hook
-     pa_assert(stream);
-     pa_assert(call_data);
-+    if (!stream->volume_control)
-+        return PA_HOOK_OK;
-+
-     switch (stream->type) {
-         case STREAM_TYPE_SINK_INPUT:
-             input = call_data;
-@@ -144,63 +135,95 @@ static pa_hook_result_t sink_input_or_source_output_volume_changed_cb(void *hook
-     if (input)
-         pa_bvolume_from_cvolume(&bvolume, &input->volume, &input->channel_map);
--    else
-+    else if (output)
-         pa_bvolume_from_cvolume(&bvolume, &output->volume, &output->channel_map);
-+    else
-+        pa_assert_not_reached();
--    pa_volume_control_volume_changed(stream->stream->own_volume_control, &bvolume, true, true);
-+    pa_volume_control_set_volume(stream->volume_control, &bvolume, true, true);
-     return PA_HOOK_OK;
- }
--static void volume_control_set_initial_volume_cb(pa_volume_control *control) {
-+static int relative_volume_control_set_volume_cb(pa_volume_control *control, const pa_bvolume *original_volume,
-+                                                 const pa_bvolume *remapped_volume, bool set_volume, bool set_balance) {
-     struct stream *stream;
-+    pa_bvolume bvolume;
-     pa_cvolume cvolume;
-     pa_assert(control);
-+    pa_assert(original_volume);
-+    pa_assert(remapped_volume);
-     stream = control->userdata;
--    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;
-+    bvolume = control->volume;
--        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;
-+    if (set_volume)
-+        bvolume.volume = remapped_volume->volume;
--    pa_assert(control);
-+    if (set_balance)
-+        pa_bvolume_copy_balance(&bvolume, remapped_volume);
--    stream = control->userdata;
-+    pa_bvolume_to_cvolume(&bvolume, &cvolume);
-     switch (stream->type) {
-         case STREAM_TYPE_SINK_INPUT:
--            pa_sink_input_set_mute(stream->sink_input, mute, true);
-+            if (stream->sink_input->state == PA_SINK_INPUT_INIT) {
-+                pa_sink_input_new_data_set_volume(stream->sink_input_new_data, &cvolume, true);
-+
-+                /* XXX: This is a bit ugly. This is needed, because when we
-+                 * call pa_sink_input_new_data_set_volume(), there's no
-+                 * automatic notification to the primary volume control object
-+                 * about the changed volume. This problem should go away once
-+                 * stream volume controls are moved into the core. */
-+                if (stream->volume_control) {
-+                    pa_bvolume absolute_volume;
-+
-+                    pa_bvolume_from_cvolume(&absolute_volume, &stream->sink_input_new_data->volume,
-+                                            &stream->sink_input_new_data->channel_map);
-+                    pa_volume_control_set_volume(stream->volume_control, &absolute_volume, true, true);
-+                }
-+            } else
-+                pa_sink_input_set_volume(stream->sink_input, &cvolume, true, false);
-             break;
-         case STREAM_TYPE_SOURCE_OUTPUT:
--            pa_source_output_set_mute(stream->source_output, mute, true);
-+            if (stream->source_output->state == PA_SOURCE_OUTPUT_INIT) {
-+                pa_source_output_new_data_set_volume(stream->source_output_new_data, &cvolume, true);
-+
-+                /* XXX: This is a bit ugly. This is needed, because when we
-+                 * call pa_source_output_new_data_set_volume(), there's no
-+                 * automatic notification to the primary volume control object
-+                 * about the changed volume. This problem should go away once
-+                 * stream volume controls are moved into the core. */
-+                if (stream->volume_control) {
-+                    pa_bvolume absolute_volume;
-+
-+                    pa_bvolume_from_cvolume(&absolute_volume, &stream->source_output_new_data->volume,
-+                                            &stream->source_output_new_data->channel_map);
-+                    pa_volume_control_set_volume(stream->volume_control, &absolute_volume, true, true);
-+                }
-+            } else
-+                pa_source_output_set_volume(stream->source_output, &cvolume, true, false);
-             break;
-     }
-     return 0;
- }
--static pa_hook_result_t sink_input_or_source_output_mute_changed_cb(void *hook_data, void *call_data, void *userdata) {
-+static pa_hook_result_t sink_input_or_source_output_reference_ratio_changed_cb(void *hook_data, void *call_data,
-+                                                                               void *userdata) {
-     struct stream *stream = userdata;
-     pa_sink_input *input = NULL;
-     pa_source_output *output = NULL;
--    bool mute;
-+    pa_bvolume bvolume;
-     pa_assert(stream);
-     pa_assert(call_data);
-+    if (!stream->relative_volume_control)
-+        return PA_HOOK_OK;
-+
-     switch (stream->type) {
-         case STREAM_TYPE_SINK_INPUT:
-             input = call_data;
-@@ -215,18 +238,18 @@ static pa_hook_result_t sink_input_or_source_output_mute_changed_cb(void *hook_d
-         return PA_HOOK_OK;
-     if (input)
--        mute = input->muted;
-+        pa_bvolume_from_cvolume(&bvolume, &input->reference_ratio, &input->channel_map);
-     else if (output)
--        mute = output->muted;
-+        pa_bvolume_from_cvolume(&bvolume, &output->reference_ratio, &output->channel_map);
-     else
-         pa_assert_not_reached();
--    pa_mute_control_mute_changed(stream->stream->own_mute_control, mute);
-+    pa_volume_control_set_volume(stream->relative_volume_control, &bvolume, true, true);
-     return PA_HOOK_OK;
- }
--static void mute_control_set_initial_mute_cb(pa_mute_control *control) {
-+static int mute_control_set_mute_cb(pa_mute_control *control, bool mute) {
-     struct stream *stream;
-     pa_assert(control);
-@@ -235,167 +258,66 @@ static void mute_control_set_initial_mute_cb(pa_mute_control *control) {
-     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);
-+            if (stream->sink_input->state == PA_SINK_INPUT_INIT)
-+                pa_sink_input_new_data_set_muted(stream->sink_input_new_data, mute);
-+            else
-+                pa_sink_input_set_mute(stream->sink_input, mute, true);
-             break;
-         case STREAM_TYPE_SOURCE_OUTPUT:
--            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);
-+            if (stream->source_output->state == PA_SOURCE_OUTPUT_INIT)
-+                pa_source_output_new_data_set_muted(stream->source_output_new_data, mute);
-+            else
-+                pa_source_output_set_mute(stream->source_output, mute, true);
-             break;
-     }
--    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);
-+    return 0;
- }
--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;
--    }
-+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;
--    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);
-+    pa_assert(call_data);
--    pa_assert(!stream->mute_changed_slot);
-+    if (!stream->mute_control)
-+        return PA_HOOK_OK;
-     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;
-+            input = call_data;
-             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;
-+            output = call_data;
-             break;
-     }
--    pa_mute_control_put(control, mute, true, mute_control_set_initial_mute_cb);
--
--    return control;
--}
-+    if ((input && input != stream->sink_input) || (output && output != stream->source_output))
-+        return PA_HOOK_OK;
--static void stream_delete_own_mute_control_cb(pas_stream *s) {
--    struct stream *stream;
-+    if (input)
-+        mute = input->muted;
-+    else if (output)
-+        mute = output->muted;
-+    else
-+        pa_assert_not_reached();
--    pa_assert(s);
-+    pa_mute_control_set_mute(stream->mute_control, mute);
--    stream = s->userdata;
--    pa_hook_slot_free(stream->mute_changed_slot);
--    stream->mute_changed_slot = NULL;
--    pa_mute_control_free(s->own_mute_control);
-+    return PA_HOOK_OK;
- }
- static pa_hook_result_t sink_input_or_source_output_proplist_changed_cb(void *hook_data, void *call_data, void *userdata) {
-     struct stream *stream = userdata;
-     pa_sink_input *input = NULL;
-     pa_source_output *output = NULL;
--    const char *new_stream_description = NULL;
--    char *new_control_description;
-+    pa_proplist *proplist = NULL;
-+    const char *description = NULL;
-     pa_assert(stream);
-     pa_assert(call_data);
-@@ -407,9 +329,7 @@ static pa_hook_result_t sink_input_or_source_output_proplist_changed_cb(void *ho
-             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;
-+            proplist = stream->sink_input->proplist;
-             break;
-         case STREAM_TYPE_SOURCE_OUTPUT:
-@@ -418,187 +338,290 @@ static pa_hook_result_t sink_input_or_source_output_proplist_changed_cb(void *ho
-             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;
-+            proplist = stream->source_output->proplist;
-             break;
-     }
--    pas_stream_description_changed(stream->stream, new_stream_description);
--
--    new_control_description = get_stream_volume_and_mute_control_description_malloc(stream);
-+    description = pa_proplist_gets(proplist, PA_PROP_MEDIA_NAME);
-+    if (!description)
-+        description = stream->stream->name;
--    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);
-+    pas_stream_set_description(stream->stream, 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;
-+static int stream_new(pa_stream_creator *creator, enum stream_type type, void *new_data, void *core_stream,
-+                      struct stream **_r) {
-+    struct stream *stream = NULL;
-+    pa_proplist *proplist = NULL;
-+    pa_channel_map *channel_map = NULL;
-+    bool volume_available = false;
-+    pa_bvolume volume;
-+    pa_bvolume relative_volume;
-+    bool mute = false;
-+    const char *stream_name = NULL;
-     const char *description = NULL;
-+    const char *volume_control_name = NULL;
-+    const char *relative_volume_control_name = NULL;
-+    const char *mute_control_name = NULL;
-     pa_direction_t direction = PA_DIRECTION_OUTPUT;
-+    int r;
-+    const char *prop_key;
-+    void *state = NULL;
-     pa_assert(creator);
-     pa_assert(core_stream);
-+    pa_assert(_r);
-+
-+    pa_bvolume_init_invalid(&volume);
-+    pa_bvolume_init_invalid(&relative_volume);
-     stream = pa_xnew0(struct stream, 1);
-+    stream->core = creator->volume_api->core;
-     stream->creator = creator;
-     stream->type = type;
-     switch (type) {
-         case STREAM_TYPE_SINK_INPUT:
-+            stream->sink_input_new_data = new_data;
-             stream->sink_input = core_stream;
--            stream->client = stream->sink_input->client;
--            name = "sink-input-stream";
--            description = get_sink_input_description(stream->sink_input);
--            if (!description)
--                description = name;
-+            if (new_data) {
-+                stream->client = stream->sink_input_new_data->client;
-+                proplist = stream->sink_input_new_data->proplist;
-+                channel_map = &stream->sink_input_new_data->channel_map;
-+                volume_available = stream->sink_input_new_data->volume_writable;
-+
-+                if (volume_available) {
-+                    if (!stream->sink_input_new_data->volume_is_set) {
-+                        pa_cvolume cvolume;
-+
-+                        pa_cvolume_reset(&cvolume, channel_map->channels);
-+                        pa_sink_input_new_data_set_volume(stream->sink_input_new_data, &cvolume, true);
-+                    }
-+
-+                    pa_bvolume_from_cvolume(&volume, &stream->sink_input_new_data->volume, channel_map);
-+                    pa_bvolume_from_cvolume(&relative_volume, &stream->sink_input_new_data->reference_ratio, channel_map);
-+                }
-+
-+                if (!stream->sink_input_new_data->muted_is_set)
-+                    pa_sink_input_new_data_set_muted(stream->sink_input_new_data, false);
-+
-+                mute = stream->sink_input_new_data->muted;
-+            } else {
-+                stream->client = stream->sink_input->client;
-+                proplist = stream->sink_input->proplist;
-+                channel_map = &stream->sink_input->channel_map;
-+                pa_bvolume_from_cvolume(&volume, &stream->sink_input->volume, channel_map);
-+                pa_bvolume_from_cvolume(&relative_volume, &stream->sink_input->reference_ratio, channel_map);
-+                mute = stream->sink_input->muted;
-+            }
-+
-+            stream_name = "sink-input-stream";
-+            volume_control_name = "sink-input-volume-control";
-+            relative_volume_control_name = "sink-input-relative-volume-control";
-+            mute_control_name = "sink-input-mute-control";
-             direction = PA_DIRECTION_OUTPUT;
-+
-+            stream->proplist_changed_slot =
-+                    pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], PA_HOOK_NORMAL,
-+                                    sink_input_or_source_output_proplist_changed_cb, stream);
-+            stream->volume_changed_slot =
-+                    pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED], PA_HOOK_NORMAL,
-+                                    sink_input_or_source_output_volume_changed_cb, stream);
-+            stream->reference_ratio_changed_slot =
-+                    pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SINK_INPUT_REFERENCE_RATIO_CHANGED], PA_HOOK_NORMAL,
-+                                    sink_input_or_source_output_reference_ratio_changed_cb, stream);
-+            stream->mute_changed_slot =
-+                    pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED], PA_HOOK_NORMAL,
-+                                    sink_input_or_source_output_mute_changed_cb, stream);
-             break;
-         case STREAM_TYPE_SOURCE_OUTPUT:
-+            stream->source_output_new_data = new_data;
-             stream->source_output = core_stream;
--            stream->client = stream->source_output->client;
--            name = "source-output-stream";
--            description = get_source_output_description(stream->source_output);
--            if (!description)
--                description = name;
-+            if (new_data) {
-+                stream->client = stream->source_output_new_data->client;
-+                proplist = stream->source_output_new_data->proplist;
-+                channel_map = &stream->source_output_new_data->channel_map;
-+                volume_available = stream->source_output_new_data->volume_writable;
-+
-+                if (volume_available) {
-+                    if (!stream->source_output_new_data->volume_is_set) {
-+                        pa_cvolume cvolume;
-+
-+                        pa_cvolume_reset(&cvolume, channel_map->channels);
-+                        pa_source_output_new_data_set_volume(stream->source_output_new_data, &cvolume, true);
-+                    }
-+
-+                    pa_bvolume_from_cvolume(&volume, &stream->source_output_new_data->volume, channel_map);
-+                    pa_bvolume_from_cvolume(&relative_volume, &stream->source_output_new_data->reference_ratio, channel_map);
-+                }
-+
-+                if (!stream->source_output_new_data->muted_is_set)
-+                    pa_source_output_new_data_set_muted(stream->source_output_new_data, false);
-+
-+                mute = stream->source_output_new_data->muted;
-+            } else {
-+                stream->client = stream->source_output->client;
-+                proplist = stream->source_output->proplist;
-+                channel_map = &stream->source_output->channel_map;
-+                pa_bvolume_from_cvolume(&volume, &stream->source_output->volume, channel_map);
-+                pa_bvolume_from_cvolume(&relative_volume, &stream->source_output->reference_ratio, channel_map);
-+                mute = stream->source_output->muted;
-+            }
-+
-+            stream_name = "source-output-stream";
-+            volume_control_name = "source-output-volume-control";
-+            relative_volume_control_name = "source-output-relative-volume-control";
-+            mute_control_name = "source-output-mute-control";
-             direction = PA_DIRECTION_INPUT;
--            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,
-+                    pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], PA_HOOK_NORMAL,
-                                     sink_input_or_source_output_proplist_changed_cb, stream);
--            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);
-+            if (volume_available) {
-+                stream->volume_changed_slot =
-+                        pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED], PA_HOOK_NORMAL,
-+                                        sink_input_or_source_output_volume_changed_cb, stream);
-+                stream->reference_ratio_changed_slot =
-+                        pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_REFERENCE_RATIO_CHANGED],
-+                                        PA_HOOK_NORMAL, sink_input_or_source_output_reference_ratio_changed_cb, stream);
-+            }
-+
-+            stream->mute_changed_slot =
-+                    pa_hook_connect(&stream->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED], PA_HOOK_NORMAL,
-+                                    sink_input_or_source_output_mute_changed_cb, stream);
-             break;
-     }
--    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);
-+    r = pas_stream_new(creator->volume_api, stream_name, &stream->stream);
-+    if (r < 0)
-+        goto fail;
--    return stream;
--}
-+    description = pa_proplist_gets(proplist, PA_PROP_MEDIA_NAME);
-+    if (!description)
-+        description = stream->stream->name;
--static void stream_put(struct stream *stream) {
--    pa_proplist *proplist = NULL;
-+    pas_stream_set_description(stream->stream, description);
--    pa_assert(stream);
-+    while ((prop_key = pa_proplist_iterate(proplist, &state)))
-+        pas_stream_set_property(stream->stream, prop_key, pa_proplist_gets(proplist, prop_key));
--    switch (stream->type) {
--        case STREAM_TYPE_SINK_INPUT:
--            proplist = stream->sink_input->proplist;
--            break;
-+    pas_stream_set_direction(stream->stream, direction);
-+    stream->stream->userdata = stream;
--        case STREAM_TYPE_SOURCE_OUTPUT:
--            proplist = stream->source_output->proplist;
--            break;
-+    if (volume_available) {
-+        r = pa_volume_control_new(stream->creator->volume_api, volume_control_name, false,
-+                                  &stream->volume_control);
-+        if (r >= 0) {
-+            pa_volume_control_set_description(stream->volume_control, _("Volume"));
-+            pa_volume_control_set_channel_map(stream->volume_control, channel_map);
-+            pa_volume_control_set_volume(stream->volume_control, &volume, true, true);
-+            pa_volume_control_set_convertible_to_dB(stream->volume_control, true);
-+            stream->volume_control->set_volume = volume_control_set_volume_cb;
-+            stream->volume_control->userdata = stream;
-+
-+            pas_stream_set_volume_control(stream->stream, stream->volume_control);
-+        }
-+
-+        r = pa_volume_control_new(stream->creator->volume_api, relative_volume_control_name, false,
-+                                  &stream->relative_volume_control);
-+        if (r >= 0) {
-+            pa_volume_control_set_description(stream->relative_volume_control, _("Relative volume"));
-+            pa_volume_control_set_channel_map(stream->relative_volume_control, channel_map);
-+            pa_volume_control_set_volume(stream->relative_volume_control, &relative_volume, true, true);
-+            pa_volume_control_set_convertible_to_dB(stream->relative_volume_control, true);
-+            pa_volume_control_set_purpose(stream->relative_volume_control, PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME,
-+                                          stream->stream);
-+            stream->relative_volume_control->set_volume = relative_volume_control_set_volume_cb;
-+            stream->relative_volume_control->userdata = stream;
-+
-+            pas_stream_set_relative_volume_control(stream->stream, stream->relative_volume_control);
-+        }
-     }
--    pas_stream_put(stream->stream, proplist);
--}
-+    r = pa_mute_control_new(stream->creator->volume_api, mute_control_name, false, &stream->mute_control);
-+    if (r >= 0) {
-+        pa_mute_control_set_description(stream->mute_control, _("Mute"));
-+        pa_mute_control_set_mute(stream->mute_control, mute);
-+        pa_mute_control_set_purpose(stream->mute_control, PA_MUTE_CONTROL_PURPOSE_STREAM_MUTE, stream->stream);
-+        stream->mute_control->set_mute = mute_control_set_mute_cb;
-+        stream->mute_control->userdata = stream;
--static void stream_unlink(struct stream *stream) {
--    pa_assert(stream);
-+        pas_stream_set_mute_control(stream->stream, stream->mute_control);
-+    }
--    if (stream->unlinked)
--        return;
-+    pas_stream_put(stream->stream);
--    stream->unlinked = true;
-+    if (stream->volume_control)
-+        pa_volume_control_put(stream->volume_control);
--    if (stream->stream)
--        pas_stream_unlink(stream->stream);
-+    if (stream->relative_volume_control)
-+        pa_volume_control_put(stream->relative_volume_control);
-+
-+    if (stream->mute_control)
-+        pa_mute_control_put(stream->mute_control);
-+
-+    *_r = stream;
-+    return 0;
-+
-+fail:
-+    if (stream)
-+        stream_free(stream);
-+
-+    return r;
- }
- static void stream_free(struct stream *stream) {
-     pa_assert(stream);
--    if (!stream->unlinked)
--        stream_unlink(stream);
-+    if (stream->mute_changed_slot)
-+        pa_hook_slot_free(stream->mute_changed_slot);
-+
-+    if (stream->reference_ratio_changed_slot)
-+        pa_hook_slot_free(stream->reference_ratio_changed_slot);
--    if (stream->client_proplist_changed_slot)
--        pa_hook_slot_free(stream->client_proplist_changed_slot);
-+    if (stream->volume_changed_slot)
-+        pa_hook_slot_free(stream->volume_changed_slot);
-     if (stream->proplist_changed_slot)
-         pa_hook_slot_free(stream->proplist_changed_slot);
-+    if (stream->mute_control)
-+        pa_mute_control_free(stream->mute_control);
-+
-+    if (stream->relative_volume_control)
-+        pa_volume_control_free(stream->relative_volume_control);
-+
-+    if (stream->volume_control)
-+        pa_volume_control_free(stream->volume_control);
-+
-     if (stream->stream)
-         pas_stream_free(stream->stream);
-     pa_xfree(stream);
- }
--static void create_stream(pa_stream_creator *creator, enum stream_type type, void *core_stream) {
-+static pa_hook_result_t sink_input_fixate_cb(void *hook_data, void *call_data, void *userdata) {
-+    pa_stream_creator *creator = userdata;
-+    pa_sink_input_new_data *data = call_data;
-+    int r;
-     struct stream *stream;
-     pa_assert(creator);
--    pa_assert(core_stream);
-+    pa_assert(data);
--    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);
-+    r = stream_new(creator, STREAM_TYPE_SINK_INPUT, data, data->sink_input, &stream);
-+    if (r < 0)
-+        return PA_HOOK_OK;
--    create_stream(creator, STREAM_TYPE_SINK_INPUT, input);
-+    pa_hashmap_put(creator->streams, stream->sink_input, stream);
-     return PA_HOOK_OK;
- }
-@@ -615,14 +638,20 @@ static pa_hook_result_t sink_input_unlink_cb(void *hook_data, void *call_data, v
-     return PA_HOOK_OK;
- }
--static pa_hook_result_t source_output_put_cb(void *hook_data, void *call_data, void *userdata) {
-+static pa_hook_result_t source_output_fixate_cb(void *hook_data, void *call_data, void *userdata) {
-     pa_stream_creator *creator = userdata;
--    pa_source_output *output = call_data;
-+    pa_source_output_new_data *data = call_data;
-+    int r;
-+    struct stream *stream;
-     pa_assert(creator);
--    pa_assert(output);
-+    pa_assert(data);
-+
-+    r = stream_new(creator, STREAM_TYPE_SOURCE_OUTPUT, data, data->source_output, &stream);
-+    if (r < 0)
-+        return PA_HOOK_OK;
--    create_stream(creator, STREAM_TYPE_SOURCE_OUTPUT, output);
-+    pa_hashmap_put(creator->streams, stream->source_output, stream);
-     return PA_HOOK_OK;
- }
-@@ -644,26 +673,34 @@ pa_stream_creator *pa_stream_creator_new(pa_volume_api *api) {
-     uint32_t idx;
-     pa_sink_input *input;
-     pa_source_output *output;
-+    int r;
-+    struct stream *stream;
-     pa_assert(api);
-     creator = pa_xnew0(pa_stream_creator, 1);
-     creator->volume_api = api;
-     creator->streams = pa_hashmap_new_full(NULL, NULL, NULL, (pa_free_cb_t) stream_free);
--    creator->sink_input_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_fixate_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_NORMAL,
-+                                                      sink_input_fixate_cb, creator);
-     creator->sink_input_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_NORMAL,
-                                                       sink_input_unlink_cb, creator);
--    creator->source_output_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_fixate_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], PA_HOOK_NORMAL,
-+                                                         source_output_fixate_cb, creator);
-     creator->source_output_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_NORMAL,
-                                                          source_output_unlink_cb, creator);
--    PA_IDXSET_FOREACH(input, api->core->sink_inputs, idx)
--        create_stream(creator, STREAM_TYPE_SINK_INPUT, input);
-+    PA_IDXSET_FOREACH(input, api->core->sink_inputs, idx) {
-+        r = stream_new(creator, STREAM_TYPE_SINK_INPUT, NULL, input, &stream);
-+        if (r >= 0)
-+            pa_hashmap_put(creator->streams, stream->sink_input, stream);
-+    }
--    PA_IDXSET_FOREACH(output, api->core->source_outputs, idx)
--        create_stream(creator, STREAM_TYPE_SOURCE_OUTPUT, output);
-+    PA_IDXSET_FOREACH(output, api->core->source_outputs, idx) {
-+        r = stream_new(creator, STREAM_TYPE_SOURCE_OUTPUT, NULL, output, &stream);
-+        if (r >= 0)
-+            pa_hashmap_put(creator->streams, stream->source_output, stream);
-+    }
-     return creator;
- }
-@@ -677,14 +714,14 @@ void pa_stream_creator_free(pa_stream_creator *creator) {
-     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->source_output_fixate_slot)
-+        pa_hook_slot_free(creator->source_output_fixate_slot);
-     if (creator->sink_input_unlink_slot)
-         pa_hook_slot_free(creator->sink_input_unlink_slot);
--    if (creator->sink_input_put_slot)
--        pa_hook_slot_free(creator->sink_input_put_slot);
-+    if (creator->sink_input_fixate_slot)
-+        pa_hook_slot_free(creator->sink_input_fixate_slot);
-     if (creator->streams)
-         pa_hashmap_free(creator->streams);
-diff --git a/src/modules/volume-api/volume-api.c b/src/modules/volume-api/volume-api.c
-index 9abea7e..4a8a2e6 100644
---- a/src/modules/volume-api/volume-api.c
-+++ b/src/modules/volume-api/volume-api.c
-@@ -26,16 +26,20 @@
- #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/inidb.h>
- #include <modules/volume-api/sstream.h>
- #include <modules/volume-api/stream-creator.h>
- #include <modules/volume-api/volume-control.h>
- #include <pulsecore/core-util.h>
-+#include <pulsecore/namereg.h>
- #include <pulsecore/shared.h>
-+#define CONTROL_DB_TABLE_NAME_VOLUME_CONTROL "VolumeControl"
-+#define CONTROL_DB_TABLE_NAME_MUTE_CONTROL "MuteControl"
-+
- static pa_volume_api *volume_api_new(pa_core *core);
- static void volume_api_free(pa_volume_api *api);
-@@ -76,44 +80,209 @@ 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) {
--    pa_assert(api);
--    pa_assert(type);
-+static int control_db_get_volume_control_cb(pa_inidb *db, const char *name, void **_r) {
-+    pa_volume_api *api;
-+    pa_volume_control *control;
-+
-+    pa_assert(db);
-+    pa_assert(name);
-+    pa_assert(_r);
-+
-+    api = pa_inidb_get_userdata(db);
--    pa_assert_se(pa_hashmap_put(api->binding_target_types, type->name, type) >= 0);
-+    control = pa_hashmap_get(api->volume_controls_from_db, name);
-+    if (!control) {
-+        int r;
--    pa_log_debug("Added binding target type %s.", type->name);
-+        r = pa_volume_control_new(api, name, true, &control);
-+        if (r < 0)
-+            return r;
--    pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_ADDED], type);
-+        pa_hashmap_put(api->volume_controls_from_db, (void *) control->name, control);
-+    }
-+
-+    *_r = control;
-+    return 0;
- }
--void pa_volume_api_remove_binding_target_type(pa_volume_api *api, pa_binding_target_type *type) {
--    pa_assert(api);
--    pa_assert(type);
-+static int control_db_parse_volume_control_description_cb(pa_inidb *db, const char *value, void *object) {
-+    pa_volume_control *control = object;
-+
-+    pa_assert(db);
-+    pa_assert(value);
-+    pa_assert(control);
--    pa_log_debug("Removing binding target type %s.", type->name);
-+    pa_volume_control_set_description(control, value);
--    pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_REMOVED], type);
-+    return 0;
-+}
-+
-+static int control_db_parse_volume_control_volume_cb(pa_inidb *db, const char *value, void *object) {
-+    pa_volume_control *control = object;
-+    int r;
-+    pa_bvolume bvolume;
-+
-+    pa_assert(db);
-+    pa_assert(value);
-+    pa_assert(control);
-+
-+    r = pa_atou(value, &bvolume.volume);
-+    if (r < 0)
-+        return -PA_ERR_INVALID;
-+
-+    if (!PA_VOLUME_IS_VALID(bvolume.volume))
-+        return -PA_ERR_INVALID;
--    pa_assert_se(pa_hashmap_remove(api->binding_target_types, type->name));
-+    pa_volume_control_set_volume(control, &bvolume, true, false);
-+
-+    return 0;
- }
--static void create_builtin_binding_target_types(pa_volume_api *api) {
--    pa_binding_target_type *type;
-+static int control_db_parse_volume_control_balance_cb(pa_inidb *db, const char *value, void *object) {
-+    pa_volume_control *control = object;
-+    int r;
-+    pa_bvolume bvolume;
--    pa_assert(api);
-+    pa_assert(db);
-+    pa_assert(value);
-+    pa_assert(control);
-+
-+    r = pa_bvolume_parse_balance(value, &bvolume);
-+    if (r < 0)
-+        return -PA_ERR_INVALID;
-+
-+    pa_volume_control_set_channel_map(control, &bvolume.channel_map);
-+    pa_volume_control_set_volume(control, &bvolume, false, true);
-+
-+    return 0;
-+}
-+
-+static int control_db_parse_volume_control_convertible_to_dB_cb(pa_inidb *db, const char *value, void *object) {
-+    pa_volume_control *control = object;
-+    int r;
-+
-+    pa_assert(db);
-+    pa_assert(value);
-+    pa_assert(control);
-+
-+    r = pa_parse_boolean(value);
-+    if (r < 0)
-+        return -PA_ERR_INVALID;
-+
-+    pa_volume_control_set_convertible_to_dB(control, r);
-+
-+    return 0;
-+}
-+
-+static int control_db_get_mute_control_cb(pa_inidb *db, const char *name, void **_r) {
-+    pa_volume_api *api;
-+    pa_mute_control *control;
-+
-+    pa_assert(db);
-+    pa_assert(name);
-+    pa_assert(_r);
-+
-+    api = pa_inidb_get_userdata(db);
-+
-+    control = pa_hashmap_get(api->mute_controls_from_db, name);
-+    if (!control) {
-+        int r;
-+
-+        r = pa_mute_control_new(api, name, true, &control);
-+        if (r < 0)
-+            return r;
-+
-+        pa_hashmap_put(api->mute_controls_from_db, (void *) control->name, control);
-+    }
-+
-+    *_r = control;
-+    return 0;
-+}
-+
-+static int control_db_parse_mute_control_description_cb(pa_inidb *db, const char *value, void *object) {
-+    pa_mute_control *control = object;
--    type = pa_audio_group_create_binding_target_type(api);
--    pa_volume_api_add_binding_target_type(api, type);
-+    pa_assert(db);
-+    pa_assert(value);
-+    pa_assert(control);
-+
-+    pa_mute_control_set_description(control, value);
-+
-+    return 0;
- }
--static void delete_builtin_binding_target_types(pa_volume_api *api) {
--    pa_binding_target_type *type;
-+static int control_db_parse_mute_control_mute_cb(pa_inidb *db, const char *value, void *object) {
-+    pa_mute_control *control = object;
-+    int mute;
-+
-+    pa_assert(db);
-+    pa_assert(value);
-+    pa_assert(control);
-+
-+    mute = pa_parse_boolean(value);
-+    if (mute < 0)
-+        return -PA_ERR_INVALID;
-+
-+    pa_mute_control_set_mute(control, mute);
-+
-+    return 0;
-+}
-+
-+static void create_control_db(pa_volume_api *api) {
-+    pa_volume_control *volume_control;
-+    pa_mute_control *mute_control;
-+
-+    pa_assert(api);
-+    pa_assert(!api->control_db.db);
-+
-+    api->control_db.db = pa_inidb_new(api->core, "controls", api);
-+
-+    api->control_db.volume_controls = pa_inidb_add_table(api->control_db.db, CONTROL_DB_TABLE_NAME_VOLUME_CONTROL,
-+                                                         control_db_get_volume_control_cb);
-+    pa_inidb_table_add_column(api->control_db.volume_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_DESCRIPTION,
-+                              control_db_parse_volume_control_description_cb);
-+    pa_inidb_table_add_column(api->control_db.volume_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_VOLUME,
-+                              control_db_parse_volume_control_volume_cb);
-+    pa_inidb_table_add_column(api->control_db.volume_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_BALANCE,
-+                              control_db_parse_volume_control_balance_cb);
-+    pa_inidb_table_add_column(api->control_db.volume_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_CONVERTIBLE_TO_DB,
-+                              control_db_parse_volume_control_convertible_to_dB_cb);
-+
-+    api->control_db.mute_controls = pa_inidb_add_table(api->control_db.db, CONTROL_DB_TABLE_NAME_MUTE_CONTROL,
-+                                                       control_db_get_mute_control_cb);
-+    pa_inidb_table_add_column(api->control_db.mute_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_DESCRIPTION,
-+                              control_db_parse_mute_control_description_cb);
-+    pa_inidb_table_add_column(api->control_db.mute_controls, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_MUTE,
-+                              control_db_parse_mute_control_mute_cb);
-+
-+    api->volume_controls_from_db = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-+    api->mute_controls_from_db = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-+
-+    pa_inidb_load(api->control_db.db);
-+
-+    while ((volume_control = pa_hashmap_steal_first(api->volume_controls_from_db)))
-+        pa_volume_control_put(volume_control);
-+    pa_hashmap_free(api->volume_controls_from_db);
-+    api->volume_controls_from_db = NULL;
-+
-+    while ((mute_control = pa_hashmap_steal_first(api->mute_controls_from_db)))
-+        pa_mute_control_put(mute_control);
-+
-+    pa_hashmap_free(api->mute_controls_from_db);
-+    api->mute_controls_from_db = NULL;
-+}
-+
-+static void delete_control_db(pa_volume_api *api) {
-     pa_assert(api);
--    type = pa_hashmap_get(api->binding_target_types, PA_AUDIO_GROUP_BINDING_TARGET_TYPE);
--    pa_volume_api_remove_binding_target_type(api, type);
-+    if (!api->control_db.db)
-+        return;
-+
-+    pa_inidb_free(api->control_db.db);
-+    api->control_db.mute_controls = NULL;
-+    api->control_db.volume_controls = NULL;
-+    api->control_db.db = NULL;
- }
- static void create_objects_defer_event_cb(pa_mainloop_api *mainloop_api, pa_defer_event *event, void *userdata) {
-@@ -138,7 +307,6 @@ static pa_volume_api *volume_api_new(pa_core *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);
-@@ -149,7 +317,7 @@ static pa_volume_api *volume_api_new(pa_core *core) {
-     for (i = 0; i < PA_VOLUME_API_HOOK_MAX; i++)
-         pa_hook_init(&api->hooks[i], api);
--    create_builtin_binding_target_types(api);
-+    create_control_db(api);
-     /* We delay the object creation to ensure that policy modules have a chance
-      * to affect the initialization of the objects. If we created the objects
-@@ -170,6 +338,9 @@ static void volume_api_free(pa_volume_api *api) {
-     pa_log_debug("Freeing the pa_volume_api object.");
-+    pa_assert(!api->mute_controls_from_db);
-+    pa_assert(!api->volume_controls_from_db);
-+
-     if (api->stream_creator)
-         pa_stream_creator_free(api->stream_creator);
-@@ -179,8 +350,7 @@ static void volume_api_free(pa_volume_api *api) {
-     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);
-+    delete_control_db(api);
-     for (i = 0; i < PA_VOLUME_API_HOOK_MAX; i++)
-         pa_hook_done(&api->hooks[i]);
-@@ -201,12 +371,24 @@ static void volume_api_free(pa_volume_api *api) {
-     }
-     if (api->mute_controls) {
--        pa_assert(pa_hashmap_isempty(api->mute_controls));
-+        pa_mute_control *control;
-+
-+        while ((control = pa_hashmap_first(api->mute_controls))) {
-+            pa_assert(!control->present);
-+            pa_mute_control_free(control);
-+        }
-+
-         pa_hashmap_free(api->mute_controls);
-     }
-     if (api->volume_controls) {
--        pa_assert(pa_hashmap_isempty(api->volume_controls));
-+        pa_volume_control *control;
-+
-+        while ((control = pa_hashmap_first(api->volume_controls))) {
-+            pa_assert(!control->present);
-+            pa_volume_control_free(control);
-+        }
-+
-         pa_hashmap_free(api->volume_controls);
-     }
-@@ -215,11 +397,6 @@ static void volume_api_free(pa_volume_api *api) {
-         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);
- }
-@@ -231,19 +408,24 @@ int pa_volume_api_register_name(pa_volume_api *api, const char *requested_name,
-     pa_assert(requested_name);
-     pa_assert(registered_name);
-+    if (!pa_namereg_is_valid_name(requested_name)) {
-+        pa_log("Invalid name: \"%s\"", requested_name);
-+        return -PA_ERR_INVALID;
-+    }
-+
-     n = pa_xstrdup(requested_name);
-     if (pa_hashmap_put(api->names, n, n) < 0) {
-         unsigned i = 1;
--        pa_xfree(n);
--
-         if (fail_if_already_registered) {
-+            pa_xfree(n);
-             pa_log("Name %s already registered.", requested_name);
-             return -PA_ERR_EXIST;
-         }
-         do {
-+            pa_xfree(n);
-             i++;
-             n = pa_sprintf_malloc("%s.%u", requested_name, i);
-         } while (pa_hashmap_put(api->names, n, n) < 0);
-@@ -271,38 +453,6 @@ uint32_t pa_volume_api_allocate_volume_control_index(pa_volume_api *api) {
-     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);
-@@ -318,10 +468,10 @@ int pa_volume_api_remove_volume_control(pa_volume_api *api, pa_volume_control *c
-         return -1;
-     if (control == api->main_output_volume_control)
--        set_main_output_volume_control_internal(api, NULL);
-+        pa_volume_api_set_main_output_volume_control(api, NULL);
-     if (control == api->main_input_volume_control)
--        set_main_input_volume_control_internal(api, NULL);
-+        pa_volume_api_set_main_input_volume_control(api, NULL);
-     return 0;
- }
-@@ -350,38 +500,6 @@ uint32_t pa_volume_api_allocate_mute_control_index(pa_volume_api *api) {
-     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);
-@@ -397,10 +515,10 @@ int pa_volume_api_remove_mute_control(pa_volume_api *api, pa_mute_control *contr
-         return -1;
-     if (control == api->main_output_mute_control)
--        set_main_output_mute_control_internal(api, NULL);
-+        pa_volume_api_set_main_output_mute_control(api, NULL);
-     if (control == api->main_input_mute_control)
--        set_main_input_mute_control_internal(api, NULL);
-+        pa_volume_api_set_main_input_mute_control(api, NULL);
-     return 0;
- }
-@@ -543,105 +661,73 @@ pa_audio_group *pa_volume_api_get_audio_group_by_index(pa_volume_api *api, uint3
- }
- void pa_volume_api_set_main_output_volume_control(pa_volume_api *api, pa_volume_control *control) {
-+    pa_volume_control *old_control;
-+
-     pa_assert(api);
--    if (api->main_output_volume_control_binding) {
--        pa_binding_free(api->main_output_volume_control_binding);
--        api->main_output_volume_control_binding = NULL;
--    }
-+    old_control = api->main_output_volume_control;
--    set_main_output_volume_control_internal(api, control);
--}
-+    if (control == old_control)
-+        return;
--void pa_volume_api_set_main_input_volume_control(pa_volume_api *api, pa_volume_control *control) {
--    pa_assert(api);
-+    api->main_output_volume_control = control;
--    if (api->main_input_volume_control_binding) {
--        pa_binding_free(api->main_input_volume_control_binding);
--        api->main_input_volume_control_binding = NULL;
--    }
-+    pa_log_debug("Main output volume control changed from %s to %s.", old_control ? old_control->name : "(unset)",
-+                 control ? control->name : "(unset)");
--    set_main_input_volume_control_internal(api, control);
-+    pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED], api);
- }
--void pa_volume_api_set_main_output_mute_control(pa_volume_api *api, pa_mute_control *control) {
-+void pa_volume_api_set_main_input_volume_control(pa_volume_api *api, pa_volume_control *control) {
-+    pa_volume_control *old_control;
-+
-     pa_assert(api);
--    if (api->main_output_mute_control_binding) {
--        pa_binding_free(api->main_output_mute_control_binding);
--        api->main_output_mute_control_binding = NULL;
--    }
-+    old_control = api->main_input_volume_control;
--    set_main_output_mute_control_internal(api, control);
--}
-+    if (control == old_control)
-+        return;
--void pa_volume_api_set_main_input_mute_control(pa_volume_api *api, pa_mute_control *control) {
--    pa_assert(api);
-+    api->main_input_volume_control = control;
--    if (api->main_input_mute_control_binding) {
--        pa_binding_free(api->main_input_mute_control_binding);
--        api->main_input_mute_control_binding = NULL;
--    }
-+    pa_log_debug("Main input volume control changed from %s to %s.", old_control ? old_control->name : "(unset)",
-+                 control ? control->name : "(unset)");
--    set_main_input_mute_control_internal(api, control);
-+    pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_INPUT_VOLUME_CONTROL_CHANGED], api);
- }
--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,
--    };
-+void pa_volume_api_set_main_output_mute_control(pa_volume_api *api, pa_mute_control *control) {
-+    pa_mute_control *old_control;
-     pa_assert(api);
--    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);
--}
-+    old_control = api->main_output_mute_control;
--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,
--    };
-+    if (control == old_control)
-+        return;
--    pa_assert(api);
--    pa_assert(target_info);
-+    api->main_output_mute_control = control;
--    if (api->main_input_volume_control_binding)
--        pa_binding_free(api->main_input_volume_control_binding);
-+    pa_log_debug("Main output mute control changed from %s to %s.", old_control ? old_control->name : "(unset)",
-+                 control ? control->name : "(unset)");
--    api->main_input_volume_control_binding = pa_binding_new(api, &owner_info, target_info);
-+    pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_OUTPUT_MUTE_CONTROL_CHANGED], api);
- }
--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,
--    };
-+void pa_volume_api_set_main_input_mute_control(pa_volume_api *api, pa_mute_control *control) {
-+    pa_mute_control *old_control;
-     pa_assert(api);
--    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);
--}
-+    old_control = api->main_input_mute_control;
--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,
--    };
-+    if (control == old_control)
-+        return;
--    pa_assert(api);
--    pa_assert(target_info);
-+    api->main_input_mute_control = control;
--    if (api->main_input_mute_control_binding)
--        pa_binding_free(api->main_input_mute_control_binding);
-+    pa_log_debug("Main input mute control changed from %s to %s.", old_control ? old_control->name : "(unset)",
-+                 control ? control->name : "(unset)");
--    api->main_input_mute_control_binding = pa_binding_new(api, &owner_info, target_info);
-+    pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_INPUT_MUTE_CONTROL_CHANGED], api);
- }
-diff --git a/src/modules/volume-api/volume-api.h b/src/modules/volume-api/volume-api.h
-index 73a1410..f99182a 100644
---- a/src/modules/volume-api/volume-api.h
-+++ b/src/modules/volume-api/volume-api.h
-@@ -24,27 +24,56 @@
- #include <pulsecore/core.h>
-+#define PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_DESCRIPTION "description"
-+#define PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_VOLUME "volume"
-+#define PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_BALANCE "balance"
-+#define PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_CONVERTIBLE_TO_DB "convertible-to-dB"
-+#define PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_MUTE "mute"
-+
- typedef struct pa_volume_api pa_volume_api;
- /* Avoid circular dependencies... */
- typedef struct pa_audio_group pa_audio_group;
--typedef struct pa_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_inidb pa_inidb;
-+typedef struct pa_inidb_table pa_inidb_table;
- typedef struct pa_mute_control pa_mute_control;
- typedef struct pas_stream pas_stream;
- typedef struct pa_stream_creator pa_stream_creator;
- typedef struct pa_volume_control pa_volume_control;
- enum {
--    PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_ADDED,
--    PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_REMOVED,
-+    /* This is fired after the volume control implementation has done its part
-+     * of the volume control initialization, but before policy modules have
-+     * done their part of the initialization. Hook users are expected to not
-+     * modify the volume control state in this hook. */
-+    PA_VOLUME_API_HOOK_VOLUME_CONTROL_IMPLEMENTATION_INITIALIZED,
-+
-+    /* Policy modules can use this hook to initialize the volume control
-+     * volume. This is fired before PUT. If a policy module sets the volume, it
-+     * should return PA_HOOK_STOP to prevent lower-priority policy modules from
-+     * modifying the volume. */
-+    PA_VOLUME_API_HOOK_VOLUME_CONTROL_SET_INITIAL_VOLUME,
-+
-     PA_VOLUME_API_HOOK_VOLUME_CONTROL_PUT,
-     PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK,
-     PA_VOLUME_API_HOOK_VOLUME_CONTROL_DESCRIPTION_CHANGED,
-     PA_VOLUME_API_HOOK_VOLUME_CONTROL_VOLUME_CHANGED,
-+    PA_VOLUME_API_HOOK_VOLUME_CONTROL_CONVERTIBLE_TO_DB_CHANGED,
-+
-+    /* This is fired after the mute control implementation has done its part of
-+     * the mute control initialization, but before policy modules have done
-+     * their part of the initialization. Hook users are expected to not modify
-+     * the mute control state in this hook. */
-+    PA_VOLUME_API_HOOK_MUTE_CONTROL_IMPLEMENTATION_INITIALIZED,
-+
-+    /* Policy modules can use this hook to initialize the mute control mute.
-+     * This is fired before PUT. If a policy module sets the mute, it should
-+     * return PA_HOOK_STOP to prevent lower-priority policy modules from
-+     * modifying the mute. */
-+    PA_VOLUME_API_HOOK_MUTE_CONTROL_SET_INITIAL_MUTE,
-+
-     PA_VOLUME_API_HOOK_MUTE_CONTROL_PUT,
-     PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK,
-     PA_VOLUME_API_HOOK_MUTE_CONTROL_DESCRIPTION_CHANGED,
-@@ -54,26 +83,16 @@ enum {
-     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_PROPLIST_CHANGED,
-     PA_VOLUME_API_HOOK_STREAM_VOLUME_CONTROL_CHANGED,
-+    PA_VOLUME_API_HOOK_STREAM_RELATIVE_VOLUME_CONTROL_CHANGED,
-     PA_VOLUME_API_HOOK_STREAM_MUTE_CONTROL_CHANGED,
-     PA_VOLUME_API_HOOK_AUDIO_GROUP_PUT,
-     PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK,
-+    PA_VOLUME_API_HOOK_AUDIO_GROUP_DESCRIPTION_CHANGED,
-     PA_VOLUME_API_HOOK_AUDIO_GROUP_VOLUME_CONTROL_CHANGED,
-     PA_VOLUME_API_HOOK_AUDIO_GROUP_MUTE_CONTROL_CHANGED,
-     PA_VOLUME_API_HOOK_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED,
-@@ -86,7 +105,6 @@ enum {
- 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 */
-@@ -103,27 +121,28 @@ struct pa_volume_api {
-     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];
-+
-+    struct {
-+        pa_inidb *db;
-+        pa_inidb_table *volume_controls;
-+        pa_inidb_table *mute_controls;
-+    } control_db;
-+
-     pa_defer_event *create_objects_defer_event;
-     pa_device_creator *device_creator;
-     pa_stream_creator *stream_creator;
-+
-+    pa_hashmap *volume_controls_from_db; /* control name -> pa_volume_control, only used during initialization. */
-+    pa_hashmap *mute_controls_from_db; /* control name -> pa_mute_control, only used during initialization. */
- };
- pa_volume_api *pa_volume_api_get(pa_core *core);
- pa_volume_api *pa_volume_api_ref(pa_volume_api *api);
- void pa_volume_api_unref(pa_volume_api *api);
--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);
-@@ -155,9 +174,5 @@ void pa_volume_api_set_main_output_volume_control(pa_volume_api *api, pa_volume_
- 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
-index c7f5dbb..bf4db71 100644
---- a/src/modules/volume-api/volume-control.c
-+++ b/src/modules/volume-api/volume-control.c
-@@ -27,88 +27,96 @@
- #include <modules/volume-api/audio-group.h>
- #include <modules/volume-api/device.h>
-+#include <modules/volume-api/inidb.h>
- #include <modules/volume-api/sstream.h>
- #include <pulsecore/core-util.h>
--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;
-+int pa_volume_control_new(pa_volume_api *api, const char *name, bool persistent, pa_volume_control **_r) {
-+    pa_volume_control *control = NULL;
-+    int r;
-     pa_assert(api);
-     pa_assert(name);
--    pa_assert(description);
-+    pa_assert(_r);
-     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);
-+
-+    r = pa_volume_api_register_name(api, name, persistent, &control->name);
-+    if (r < 0)
-+        goto fail;
-+
-+    control->description = pa_xstrdup(control->name);
-     control->proplist = pa_proplist_new();
--    pa_bvolume_init_invalid(&control->volume);
--    control->convertible_to_dB = convertible_to_dB;
--    control->channel_map_is_writable = channel_map_is_writable;
-+    pa_bvolume_init_mono(&control->volume, PA_VOLUME_NORM);
-+    control->present = !persistent;
-+    control->persistent = persistent;
-+    control->purpose = PA_VOLUME_CONTROL_PURPOSE_OTHER;
-     control->devices = pa_hashmap_new(NULL, NULL);
-     control->default_for_devices = pa_hashmap_new(NULL, NULL);
--    control->streams = pa_hashmap_new(NULL, NULL);
--    control->audio_groups = pa_hashmap_new(NULL, NULL);
--    return control;
-+    if (persistent) {
-+        pa_inidb_row *row;
-+
-+        row = pa_inidb_table_add_row(api->control_db.volume_controls, control->name);
-+        control->db_cells.description = pa_inidb_row_get_cell(row, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_DESCRIPTION);
-+        control->db_cells.volume = pa_inidb_row_get_cell(row, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_VOLUME);
-+        control->db_cells.balance = pa_inidb_row_get_cell(row, PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_BALANCE);
-+        control->db_cells.convertible_to_dB = pa_inidb_row_get_cell(row,
-+                                                                    PA_VOLUME_API_CONTROL_DB_COLUMN_NAME_CONVERTIBLE_TO_DB);
-+    }
-+
-+    *_r = control;
-+    return 0;
-+
-+fail:
-+    if (control)
-+        pa_volume_control_free(control);
-+
-+    return r;
- }
--void pa_volume_control_put(pa_volume_control *control, const pa_bvolume *initial_volume,
--                           pa_volume_control_set_initial_volume_cb_t set_initial_volume_cb) {
-+void pa_volume_control_put(pa_volume_control *control) {
-     const char *prop_key;
-     void *state = NULL;
-     char volume_str[PA_VOLUME_SNPRINT_VERBOSE_MAX];
-     char balance_str[PA_BVOLUME_SNPRINT_BALANCE_MAX];
-     pa_assert(control);
--    pa_assert((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);
--    }
-+    pa_assert(control->set_volume || !control->present);
--    if (set_initial_volume_cb)
--        set_initial_volume_cb(control);
-+    pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_IMPLEMENTATION_INITIALIZED], control);
-+    pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_SET_INITIAL_VOLUME], control);
--    pa_volume_api_add_volume_control(control->volume_api, control);
-+    if (control->set_volume) {
-+        control->set_volume_in_progress = true;
-+        control->set_volume(control, &control->volume, &control->volume, true, true);
-+        control->set_volume_in_progress = false;
-+    }
-+    pa_volume_api_add_volume_control(control->volume_api, control);
-     control->linked = true;
-     pa_log_debug("Created volume control #%u.", control->index);
-     pa_log_debug("    Name: %s", control->name);
-     pa_log_debug("    Description: %s", control->description);
-+    pa_log_debug("    Volume: %s", pa_volume_snprint_verbose(volume_str, sizeof(volume_str), control->volume.volume,
-+                 control->convertible_to_dB));
-+    pa_log_debug("    Balance: %s", pa_bvolume_snprint_balance(balance_str, sizeof(balance_str), &control->volume));
-+    pa_log_debug("    Present: %s", pa_yes_no(control->present));
-+    pa_log_debug("    Persistent: %s", pa_yes_no(control->persistent));
-     pa_log_debug("    Properties:");
-     while ((prop_key = pa_proplist_iterate(control->proplist, &state)))
-         pa_log_debug("        %s = %s", prop_key, pa_strnull(pa_proplist_gets(control->proplist, prop_key)));
--    pa_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);
-@@ -122,15 +130,9 @@ void pa_volume_control_unlink(pa_volume_control *control) {
-     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);
-+        pa_volume_api_remove_volume_control(control->volume_api, control);
--    while ((stream = pa_hashmap_first(control->streams)))
--        pas_stream_set_volume_control(stream, NULL);
-+    pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK], control);
-     while ((device = pa_hashmap_first(control->default_for_devices)))
-         pa_device_set_default_volume_control(device, NULL);
-@@ -153,19 +155,10 @@ void pa_volume_control_unlink(pa_volume_control *control) {
- void pa_volume_control_free(pa_volume_control *control) {
-     pa_assert(control);
--    if (!control->unlinked)
-+    /* unlink() expects name to be set. */
-+    if (!control->unlinked && control->name)
-         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);
-@@ -187,17 +180,91 @@ void pa_volume_control_free(pa_volume_control *control) {
-     pa_xfree(control);
- }
--void pa_volume_control_set_owner_audio_group(pa_volume_control *control, pa_audio_group *group) {
-+void pa_volume_control_set_purpose(pa_volume_control *control, pa_volume_control_purpose_t purpose, void *owner) {
-+    pa_assert(control);
-+    pa_assert(!control->linked);
-+
-+    control->purpose = purpose;
-+    control->owner = owner;
-+}
-+
-+int pa_volume_control_acquire_for_audio_group(pa_volume_control *control, pa_audio_group *group,
-+                                              pa_volume_control_set_volume_cb_t set_volume_cb, void *userdata) {
-     pa_assert(control);
-     pa_assert(group);
-+    pa_assert(set_volume_cb);
-+
-+    if (control->present) {
-+        pa_log("Can't acquire volume control %s, it's already present.", control->name);
-+        return -PA_ERR_BUSY;
-+    }
-+
-+    control->set_volume = set_volume_cb;
-+    control->userdata = userdata;
-+
-+    control->set_volume_in_progress = true;
-+    control->set_volume(control, &control->volume, &control->volume, true, true);
-+    control->set_volume_in_progress = false;
-+
-+    control->present = true;
-+
-+    if (!control->linked || control->unlinked)
-+        return 0;
-+
-+    pa_log_debug("Volume control %s became present.", control->name);
-+
-+    return 0;
-+}
-+
-+void pa_volume_control_release(pa_volume_control *control) {
-+    pa_assert(control);
-+
-+    if (!control->present)
-+        return;
-+
-+    control->present = false;
-+
-+    control->userdata = NULL;
-+    control->set_volume = NULL;
-+
-+    if (!control->linked || control->unlinked)
-+        return;
-+
-+    pa_log_debug("Volume control %s became not present.", control->name);
-+}
-+
-+void pa_volume_control_set_description(pa_volume_control *control, const char *description) {
-+    char *old_description;
-+
-+    pa_assert(control);
-+    pa_assert(description);
--    control->owner_audio_group = group;
-+    old_description = control->description;
-+
-+    if (pa_streq(description, old_description))
-+        return;
-+
-+    control->description = pa_xstrdup(description);
-+
-+    if (control->persistent)
-+        pa_inidb_cell_set_value(control->db_cells.description, description);
-+
-+    if (!control->linked || control->unlinked) {
-+        pa_xfree(old_description);
-+        return;
-+    }
-+
-+    pa_log_debug("The description of volume control %s changed from \"%s\" to \"%s\".", control->name, old_description,
-+                 description);
-+    pa_xfree(old_description);
-+    pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_DESCRIPTION_CHANGED], control);
- }
- static void set_volume_internal(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance) {
-     pa_bvolume old_volume;
-     bool volume_changed;
-     bool balance_changed;
-+    char *str;
-     pa_assert(control);
-     pa_assert(volume);
-@@ -209,12 +276,26 @@ static void set_volume_internal(pa_volume_control *control, const pa_bvolume *vo
-     if (!volume_changed && !balance_changed)
-         return;
--    if (volume_changed)
-+    if (volume_changed) {
-         control->volume.volume = volume->volume;
--    if (balance_changed)
-+        if (control->persistent) {
-+            str = pa_sprintf_malloc("%u", control->volume.volume);
-+            pa_inidb_cell_set_value(control->db_cells.volume, str);
-+            pa_xfree(str);
-+        }
-+    }
-+
-+    if (balance_changed) {
-         pa_bvolume_copy_balance(&control->volume, volume);
-+        if (control->persistent) {
-+            pa_assert_se(pa_bvolume_balance_to_string(&control->volume, &str) >= 0);
-+            pa_inidb_cell_set_value(control->db_cells.balance, str);
-+            pa_xfree(str);
-+        }
-+    }
-+
-     if (!control->linked || control->unlinked)
-         return;
-@@ -248,62 +329,69 @@ int pa_volume_control_set_volume(pa_volume_control *control, const pa_bvolume *v
-     pa_assert(control);
-     pa_assert(volume);
--    volume_local = *volume;
-+    if (control->set_volume_in_progress)
-+        return 0;
--    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;
--    }
-+    volume_local = *volume;
--    if (set_balance
--            && !control->channel_map_is_writable
--            && !pa_channel_map_equal(&volume_local.channel_map, &control->volume.channel_map))
-+    if (set_balance && !pa_channel_map_equal(&volume_local.channel_map, &control->volume.channel_map))
-         pa_bvolume_remap(&volume_local, &control->volume.channel_map);
-     if (pa_bvolume_equal(&volume_local, &control->volume, set_volume, set_balance))
-         return 0;
--    control->set_volume_in_progress = true;
--    r = control->set_volume(control, &volume_local, set_volume, set_balance);
--    control->set_volume_in_progress = false;
-+    if (control->linked && control->present) {
-+        control->set_volume_in_progress = true;
-+        r = control->set_volume(control, volume, &volume_local, set_volume, set_balance);
-+        control->set_volume_in_progress = false;
--    if (r >= 0)
--        set_volume_internal(control, &volume_local, set_volume, set_balance);
-+        if (r < 0) {
-+            pa_log("Setting the volume of volume control %s failed.", control->name);
-+            return r;
-+        }
-+    }
--    return r;
-+    set_volume_internal(control, &volume_local, set_volume, set_balance);
-+
-+    return 0;
- }
--void pa_volume_control_description_changed(pa_volume_control *control, const char *new_description) {
--    char *old_description;
-+void pa_volume_control_set_channel_map(pa_volume_control *control, const pa_channel_map *map) {
-+    pa_bvolume bvolume;
-     pa_assert(control);
--    pa_assert(new_description);
-+    pa_assert(map);
--    old_description = control->description;
--
--    if (pa_streq(new_description, old_description))
-+    if (pa_channel_map_equal(map, &control->volume.channel_map))
-         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);
-+    pa_bvolume_copy_balance(&bvolume, &control->volume);
-+    pa_bvolume_remap(&bvolume, map);
-+
-+    set_volume_internal(control, &bvolume, false, true);
- }
--void pa_volume_control_volume_changed(pa_volume_control *control, const pa_bvolume *new_volume, bool volume_changed,
--                                      bool balance_changed) {
-+void pa_volume_control_set_convertible_to_dB(pa_volume_control *control, bool convertible) {
-+    bool old_convertible;
-+
-     pa_assert(control);
--    pa_assert(new_volume);
--    if (!control->linked)
-+    old_convertible = control->convertible_to_dB;
-+
-+    if (convertible == old_convertible)
-         return;
--    if (control->set_volume_in_progress)
-+    control->convertible_to_dB = convertible;
-+
-+    if (control->persistent)
-+        pa_inidb_cell_set_value(control->db_cells.convertible_to_dB, pa_boolean_to_string(convertible));
-+
-+    if (!control->linked || control->unlinked)
-         return;
--    set_volume_internal(control, new_volume, volume_changed, balance_changed);
-+    pa_log_debug("The volume of volume control %s became %sconvertible to dB.", control->name, convertible ? "" : "not ");
-+
-+    pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_CONVERTIBLE_TO_DB_CHANGED], control);
- }
- void pa_volume_control_add_device(pa_volume_control *control, pa_device *device) {
-@@ -333,31 +421,3 @@ void pa_volume_control_remove_default_for_device(pa_volume_control *control, pa_
-     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
-index aaba758..a47ab20 100644
---- a/src/modules/volume-api/volume-control.h
-+++ b/src/modules/volume-api/volume-control.h
-@@ -23,10 +23,23 @@
- ***/
- #include <modules/volume-api/bvolume.h>
-+#include <modules/volume-api/inidb.h>
- #include <modules/volume-api/volume-api.h>
- typedef struct pa_volume_control pa_volume_control;
-+typedef enum {
-+    PA_VOLUME_CONTROL_PURPOSE_STREAM_RELATIVE_VOLUME,
-+    PA_VOLUME_CONTROL_PURPOSE_OTHER,
-+} pa_volume_control_purpose_t;
-+
-+/* Usually remapped_volume is the volume to use, because it has a matching
-+ * channel map with the control, but in case the volume needs to be propagated
-+ * to another control, original_volume can be used to avoid loss of precision
-+ * that can result from remapping. */
-+typedef int (*pa_volume_control_set_volume_cb_t)(pa_volume_control *control, const pa_bvolume *original_volume,
-+                                                 const pa_bvolume *remapped_volume, bool set_volume, bool set_balance);
-+
- struct pa_volume_control {
-     pa_volume_api *volume_api;
-     uint32_t index;
-@@ -35,65 +48,61 @@ struct pa_volume_control {
-     pa_proplist *proplist;
-     pa_bvolume volume;
-     bool convertible_to_dB;
--    bool channel_map_is_writable;
-+    bool present;
-+    bool persistent;
--    /* 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_volume_control_purpose_t purpose;
-+    union {
-+        pas_stream *owner_stream;
-+        void *owner;
-+    };
-     pa_hashmap *devices; /* pa_device -> pa_device (hashmap-as-a-set) */
-     pa_hashmap *default_for_devices; /* pa_device -> pa_device (hashmap-as-a-set) */
--    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) */
-+
-+    struct {
-+        pa_inidb_cell *description;
-+        pa_inidb_cell *volume;
-+        pa_inidb_cell *balance;
-+        pa_inidb_cell *convertible_to_dB;
-+    } db_cells;
-     bool linked;
-     bool unlinked;
-     bool set_volume_in_progress;
-     /* Called from pa_volume_control_set_volume(). The implementation is
--     * expected to return a negative error code on failure. 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);
-+     * expected to return a negative error code on failure. */
-+    pa_volume_control_set_volume_cb_t set_volume;
-     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);
--
-+int pa_volume_control_new(pa_volume_api *api, const char *name, bool persistent, pa_volume_control **_r);
-+void pa_volume_control_put(pa_volume_control *control);
- void pa_volume_control_unlink(pa_volume_control *control);
- void pa_volume_control_free(pa_volume_control *control);
--/* Called by audio-group.c only. */
--void pa_volume_control_set_owner_audio_group(pa_volume_control *control, pa_audio_group *group);
-+/* Called by the volume control implementation, before
-+ * pa_volume_control_put(). */
-+void pa_volume_control_set_purpose(pa_volume_control *control, pa_volume_control_purpose_t purpose, void *owner);
--/* Called by clients and policy modules. */
-+/* Called by the volume control implementation. */
-+int pa_volume_control_acquire_for_audio_group(pa_volume_control *control, pa_audio_group *group,
-+                                              pa_volume_control_set_volume_cb_t set_volume_cb, void *userdata);
-+
-+/* Called by the volume control implementation. This must only be called for
-+ * persistent controls; use pa_volume_control_free() for non-persistent
-+ * controls. */
-+void pa_volume_control_release(pa_volume_control *control);
-+
-+/* Called by anyone. */
-+void pa_volume_control_set_description(pa_volume_control *control, const char *description);
- int pa_volume_control_set_volume(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance);
- /* Called by the volume control implementation. */
--void pa_volume_control_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);
-+void pa_volume_control_set_channel_map(pa_volume_control *control, const pa_channel_map *map);
-+void pa_volume_control_set_convertible_to_dB(pa_volume_control *control, bool convertible);
- /* Called from device.c only. */
- void pa_volume_control_add_device(pa_volume_control *control, pa_device *device);
-@@ -101,12 +110,4 @@ void pa_volume_control_remove_device(pa_volume_control *control, pa_device *devi
- 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
-index 032e108..b81909a 100644
---- a/src/pulse/ext-volume-api.c
-+++ b/src/pulse/ext-volume-api.c
-@@ -36,6 +36,7 @@
- #include <pulsecore/i18n.h>
- #include <pulsecore/macro.h>
- #include <pulsecore/pstream-util.h>
-+#include <pulsecore/strbuf.h>
- #include <math.h>
-@@ -94,6 +95,21 @@ void pa_ext_volume_api_bvolume_init_invalid(pa_ext_volume_api_bvolume *volume) {
-     pa_channel_map_init(&volume->channel_map);
- }
-+void pa_ext_volume_api_bvolume_init(pa_ext_volume_api_bvolume *bvolume, pa_volume_t volume, pa_channel_map *map) {
-+    unsigned i;
-+
-+    pa_assert(bvolume);
-+    pa_assert(PA_VOLUME_IS_VALID(volume));
-+    pa_assert(map);
-+    pa_assert(pa_channel_map_valid(map));
-+
-+    bvolume->volume = volume;
-+    bvolume->channel_map = *map;
-+
-+    for (i = 0; i < map->channels; i++)
-+        bvolume->balance[i] = 1.0;
-+}
-+
- void pa_ext_volume_api_bvolume_init_mono(pa_ext_volume_api_bvolume *bvolume, pa_volume_t volume) {
-     pa_assert(bvolume);
-     pa_assert(PA_VOLUME_IS_VALID(volume));
-@@ -103,6 +119,67 @@ void pa_ext_volume_api_bvolume_init_mono(pa_ext_volume_api_bvolume *bvolume, pa_
-     pa_channel_map_init_mono(&bvolume->channel_map);
- }
-+int pa_ext_volume_api_bvolume_parse_balance(const char *str, pa_ext_volume_api_bvolume *_r) {
-+    pa_ext_volume_api_bvolume bvolume;
-+
-+    pa_assert(str);
-+    pa_assert(_r);
-+
-+    bvolume.channel_map.channels = 0;
-+
-+    for (;;) {
-+        const char *colon;
-+        size_t channel_name_len;
-+        char *channel_name;
-+        pa_channel_position_t position;
-+        const char *space;
-+        size_t balance_str_len;
-+        char *balance_str;
-+        int r;
-+        double balance;
-+
-+        colon = strchr(str, ':');
-+        if (!colon)
-+            return -PA_ERR_INVALID;
-+
-+        channel_name_len = colon - str;
-+        channel_name = pa_xstrndup(str, channel_name_len);
-+
-+        position = pa_channel_position_from_string(channel_name);
-+        pa_xfree(channel_name);
-+        if (position == PA_CHANNEL_POSITION_INVALID)
-+            return -PA_ERR_INVALID;
-+
-+        bvolume.channel_map.map[bvolume.channel_map.channels] = position;
-+        str = colon + 1;
-+
-+        space = strchr(str, ' ');
-+        if (space)
-+            balance_str_len = space - str;
-+        else
-+            balance_str_len = strlen(str);
-+
-+        balance_str = pa_xstrndup(str, balance_str_len);
-+
-+        r = pa_atod(balance_str, &balance);
-+        if (r < 0)
-+            return -PA_ERR_INVALID;
-+
-+        if (!pa_ext_volume_api_balance_valid(balance))
-+            return -PA_ERR_INVALID;
-+
-+        bvolume.balance[bvolume.channel_map.channels++] = balance;
-+
-+        if (space)
-+            str = space + 1;
-+        else
-+            break;
-+    }
-+
-+    pa_ext_volume_api_bvolume_copy_balance(_r, &bvolume);
-+    return 0;
-+}
-+
- int pa_ext_volume_api_bvolume_equal(const pa_ext_volume_api_bvolume *a, const pa_ext_volume_api_bvolume *b,
-                                     int check_volume, int check_balance) {
-     unsigned i;
-@@ -266,6 +343,29 @@ void pa_ext_volume_api_bvolume_set_rear_front_balance(pa_ext_volume_api_bvolume
-     volume->volume = old_volume;
- }
-+int pa_ext_volume_api_bvolume_balance_to_string(const pa_ext_volume_api_bvolume *volume, char **_r) {
-+    pa_strbuf *buf;
-+    unsigned i;
-+
-+    pa_assert(volume);
-+    pa_assert(_r);
-+
-+    if (!pa_ext_volume_api_bvolume_valid(volume, false, true))
-+        return -PA_ERR_INVALID;
-+
-+    buf = pa_strbuf_new();
-+
-+    for (i = 0; i < volume->channel_map.channels; i++) {
-+        if (i != 0)
-+            pa_strbuf_putc(buf, ' ');
-+
-+        pa_strbuf_printf(buf, "%s:%.2f", pa_channel_position_to_string(volume->channel_map.map[i]), volume->balance[i]);
-+    }
-+
-+    *_r = pa_strbuf_tostring_free(buf);
-+    return 0;
-+}
-+
- char *pa_ext_volume_api_bvolume_snprint_balance(char *buf, size_t buf_len,
-                                                 const pa_ext_volume_api_bvolume *volume) {
-     char *e;
-diff --git a/src/pulse/ext-volume-api.h b/src/pulse/ext-volume-api.h
-index 720ff39..6402f4b 100644
---- a/src/pulse/ext-volume-api.h
-+++ b/src/pulse/ext-volume-api.h
-@@ -50,7 +50,9 @@ int pa_ext_volume_api_balance_valid(double balance) PA_GCC_CONST;
- int pa_ext_volume_api_bvolume_valid(const pa_ext_volume_api_bvolume *volume, int check_volume, int check_balance)
-         PA_GCC_PURE;
- void pa_ext_volume_api_bvolume_init_invalid(pa_ext_volume_api_bvolume *volume);
-+void pa_ext_volume_api_bvolume_init(pa_ext_volume_api_bvolume *bvolume, pa_volume_t volume, pa_channel_map *map);
- void pa_ext_volume_api_bvolume_init_mono(pa_ext_volume_api_bvolume *bvolume, pa_volume_t volume);
-+int pa_ext_volume_api_bvolume_parse_balance(const char *str, pa_ext_volume_api_bvolume *bvolume);
- int pa_ext_volume_api_bvolume_equal(const pa_ext_volume_api_bvolume *a, const pa_ext_volume_api_bvolume *b,
-                                     int check_volume, int check_balance) PA_GCC_PURE;
- void pa_ext_volume_api_bvolume_from_cvolume(pa_ext_volume_api_bvolume *bvolume, const pa_cvolume *cvolume,
-@@ -64,6 +66,7 @@ double pa_ext_volume_api_bvolume_get_left_right_balance(const pa_ext_volume_api_
- void pa_ext_volume_api_bvolume_set_left_right_balance(pa_ext_volume_api_bvolume *volume, double balance);
- double pa_ext_volume_api_bvolume_get_rear_front_balance(const pa_ext_volume_api_bvolume *volume) PA_GCC_PURE;
- void pa_ext_volume_api_bvolume_set_rear_front_balance(pa_ext_volume_api_bvolume *volume, double balance);
-+int pa_ext_volume_api_bvolume_balance_to_string(const pa_ext_volume_api_bvolume *volume, char **_r);
- #define PA_EXT_VOLUME_API_BVOLUME_SNPRINT_BALANCE_MAX 500
- char *pa_ext_volume_api_bvolume_snprint_balance(char *buf, size_t buf_size,
-diff --git a/src/tizen-ivi/audio-groups.conf b/src/tizen-ivi/audio-groups.conf
-index 4839307..182df0d 100644
---- a/src/tizen-ivi/audio-groups.conf
-+++ b/src/tizen-ivi/audio-groups.conf
-@@ -1,33 +1,32 @@
- [General]
--audio-groups = x-tizen-ivi-call-downlink-audio-group x-tizen-ivi-navigator-output-audio-group x-tizen-ivi-default-output-audio-group
--streams = call-downlink navigator-output default-output
-+stream-rules = call-downlink navigator-output default-output
- [AudioGroup x-tizen-ivi-call-downlink-audio-group]
- description = Call downlink
--volume-control = create
--mute-control = create
-+volume-control = create:call-downlink-volume-control
-+mute-control = create:call-downlink-mute-control
- [AudioGroup x-tizen-ivi-navigator-output-audio-group]
- description = Navigator
--volume-control = create
--mute-control = create
-+volume-control = bind:AudioGroup:x-tizen-ivi-default-output-audio-group
-+mute-control = bind:AudioGroup:x-tizen-ivi-default-output-audio-group
- [AudioGroup x-tizen-ivi-default-output-audio-group]
- description = Default
--volume-control = create
--mute-control = create
-+volume-control = create:default-output-volume-control
-+mute-control = create:default-output-mute-control
--[Stream call-downlink]
-+[StreamRule call-downlink]
- match = (direction output AND property media.role=phone)
- audio-group-for-volume = x-tizen-ivi-call-downlink-audio-group
- audio-group-for-mute = x-tizen-ivi-call-downlink-audio-group
--[Stream navigator-output]
-+[StreamRule navigator-output]
- match = (direction output AND property media.role=navigator)
- audio-group-for-volume = x-tizen-ivi-navigator-output-audio-group
- audio-group-for-mute = x-tizen-ivi-navigator-output-audio-group
--[Stream default-output]
--match = (direction output)
-+[StreamRule default-output]
-+match = (direction output AND NEG property media.role=filter)
- audio-group-for-volume = x-tizen-ivi-default-output-audio-group
- audio-group-for-mute = x-tizen-ivi-default-output-audio-group
-diff --git a/src/tizen-ivi/main-volume-policy.conf b/src/tizen-ivi/main-volume-policy.conf
-index 0a83968..f2b3513 100644
---- a/src/tizen-ivi/main-volume-policy.conf
-+++ b/src/tizen-ivi/main-volume-policy.conf
-@@ -3,7 +3,6 @@ output-volume-model = by-active-main-volume-context
- input-volume-model = none
- output-mute-model = by-active-main-volume-context
- input-mute-model = none
--main-volume-contexts = x-tizen-ivi-call default
- [MainVolumeContext x-tizen-ivi-call]
- description = Call main volume context
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/change_libsystemd_to_libsystemd-login_in_configure.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/change_libsystemd_to_libsystemd-login_in_configure.patch
deleted file mode 100644 (file)
index d65cc74..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/configure.ac     2014-06-06 10:00:12.384361791 +0200
-+++ b/configure.ac     2014-06-06 09:59:26.573362703 +0200
-@@ -1158,7 +1158,7 @@
-     AS_HELP_STRING([--disable-systemd],[Disable optional systemd support]))
- AS_IF([test "x$enable_systemd" != "xno"],
--    [PKG_CHECK_MODULES(SYSTEMD, [ libsystemd ], HAVE_SYSTEMD=1, HAVE_SYSTEMD=0)],
-+    [PKG_CHECK_MODULES(SYSTEMD, [ libsystemd-login ], HAVE_SYSTEMD=1, HAVE_SYSTEMD=0)],
-     HAVE_SYSTEMD=0)
- AS_IF([test "x$enable_systemd" = "xyes" && test "x$HAVE_SYSTEMD" = "x0"],
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0/changes-to-pa-simple-api-samsung.patch b/recipes-multimedia/pulseaudio/pulseaudio_5.0/changes-to-pa-simple-api-samsung.patch
deleted file mode 100644 (file)
index a39ae06..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-From: "vivian,zhang" <vivian.zhang@intel.com>
-Date: Tue, 18 Jun 2013 16:10:15 +0800
-Subject: changes to pa simple api - samsung
-
-Change-Id: I997c02217a8dc14524480164aa0baeea901c7b4e
----
- src/Makefile.am    |    4 +-
- src/map-file       |    6 +
- src/pulse/simple.c |  278 ++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/pulse/simple.h |   28 +++++
- 4 files changed, 314 insertions(+), 2 deletions(-)
-
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 6340dbc..ebbed80 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -815,7 +815,7 @@ libpulse_la_SOURCES = \
-               pulse/volume.c pulse/volume.h \
-               pulse/xmalloc.c pulse/xmalloc.h
--libpulse_la_CFLAGS = $(AM_CFLAGS) $(LIBJSON_CFLAGS)
-+libpulse_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) $(LIBJSON_CFLAGS)
- libpulse_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) $(LTLIBICONV) $(LIBJSON_LIBS) libpulsecommon-@PA_MAJORMINOR@.la
- libpulse_la_LDFLAGS = $(AM_LDFLAGS) $(VERSIONING_LDFLAGS) -version-info $(LIBPULSE_VERSION_INFO)
-@@ -825,7 +825,7 @@ libpulse_la_LIBADD += $(DBUS_LIBS)
- endif
- libpulse_simple_la_SOURCES = pulse/simple.c pulse/simple.h
--libpulse_simple_la_CFLAGS = $(AM_CFLAGS)
-+libpulse_simple_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
- libpulse_simple_la_LIBADD = $(AM_LIBADD) libpulse.la libpulsecommon-@PA_MAJORMINOR@.la
- libpulse_simple_la_LDFLAGS = $(AM_LDFLAGS) $(VERSIONING_LDFLAGS) -version-info $(LIBPULSE_SIMPLE_VERSION_INFO)
-diff --git a/src/map-file b/src/map-file
-index 3dee7ee..a074a49 100644
---- a/src/map-file
-+++ b/src/map-file
-@@ -274,11 +274,17 @@ pa_signal_new;
- pa_signal_set_destroy;
- pa_simple_drain;
- pa_simple_flush;
-+pa_simple_mute;
- pa_simple_free;
- pa_simple_get_latency;
- pa_simple_new;
-+pa_simple_new_proplist;
- pa_simple_read;
- pa_simple_write;
-+pa_simple_set_volume;
-+pa_simple_get_stream_index;
-+pa_simple_cork;
-+pa_simple_is_corked;
- pa_stream_begin_write;
- pa_stream_cancel_write;
- pa_stream_connect_playback;
-diff --git a/src/pulse/simple.c b/src/pulse/simple.c
-index 860cd18..fa11b30 100644
---- a/src/pulse/simple.c
-+++ b/src/pulse/simple.c
-@@ -32,10 +32,12 @@
- #include <pulse/thread-mainloop.h>
- #include <pulse/xmalloc.h>
-+#include <pulsecore/native-common.h>
- #include <pulsecore/log.h>
- #include <pulsecore/macro.h>
- #include "simple.h"
-+#include "internal.h"
- struct pa_simple {
-     pa_threaded_mainloop *mainloop;
-@@ -102,6 +104,14 @@ static void context_state_cb(pa_context *c, void *userdata) {
-     }
- }
-+static void success_context_cb(pa_context *c, int success, void *userdata) {
-+      pa_simple *p = userdata;
-+      pa_assert(c);
-+      pa_assert(p);
-+
-+    p->operation_success = success;
-+    pa_threaded_mainloop_signal(p->mainloop, 0);
-+}
- static void stream_state_cb(pa_stream *s, void * userdata) {
-     pa_simple *p = userdata;
-     pa_assert(s);
-@@ -251,6 +261,122 @@ fail:
-     return NULL;
- }
-+pa_simple* pa_simple_new_proplist(
-+        const char *server,
-+        const char *name,
-+        pa_stream_direction_t dir,
-+        const char *dev,
-+        const char *stream_name,
-+        const pa_sample_spec *ss,
-+        const pa_channel_map *map,
-+        const pa_buffer_attr *attr,
-+        pa_proplist *proplist,
-+        int *rerror) {
-+
-+    pa_simple *p;
-+    int error = PA_ERR_INTERNAL, r;
-+
-+    CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL)
-+
-+    p = pa_xnew0(pa_simple, 1);
-+    p->direction = dir;
-+
-+    if (!(p->mainloop = pa_threaded_mainloop_new()))
-+        goto fail;
-+
-+    if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name)))
-+        goto fail;
-+
-+    pa_context_set_state_callback(p->context, context_state_cb, p);
-+
-+    if (pa_context_connect(p->context, server, 0, NULL) < 0) {
-+        error = pa_context_errno(p->context);
-+        goto fail;
-+    }
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+
-+    if (pa_threaded_mainloop_start(p->mainloop) < 0)
-+        goto unlock_and_fail;
-+
-+    for (;;) {
-+        pa_context_state_t state;
-+
-+        state = pa_context_get_state(p->context);
-+
-+        if (state == PA_CONTEXT_READY)
-+            break;
-+
-+        if (!PA_CONTEXT_IS_GOOD(state)) {
-+            error = pa_context_errno(p->context);
-+            goto unlock_and_fail;
-+        }
-+
-+        /* Wait until the context is ready */
-+        pa_threaded_mainloop_wait(p->mainloop);
-+    }
-+
-+    if (!(p->stream = pa_stream_new_with_proplist(p->context, stream_name, ss, map, proplist))) {
-+        error = pa_context_errno(p->context);
-+        goto unlock_and_fail;
-+    }
-+
-+    pa_stream_set_state_callback(p->stream, stream_state_cb, p);
-+    pa_stream_set_read_callback(p->stream, stream_request_cb, p);
-+    pa_stream_set_write_callback(p->stream, stream_request_cb, p);
-+    pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
-+
-+    if (dir == PA_STREAM_PLAYBACK)
-+        r = pa_stream_connect_playback(p->stream, dev, attr,
-+                                       PA_STREAM_INTERPOLATE_TIMING
-+                                       |PA_STREAM_ADJUST_LATENCY
-+                                       |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
-+    else
-+        r = pa_stream_connect_record(p->stream, dev, attr,
-+                                     PA_STREAM_INTERPOLATE_TIMING
-+                                     |PA_STREAM_ADJUST_LATENCY
-+                                     |PA_STREAM_AUTO_TIMING_UPDATE
-+                                     |PA_STREAM_START_CORKED);
-+
-+    if (r < 0) {
-+        error = pa_context_errno(p->context);
-+        goto unlock_and_fail;
-+    }
-+
-+    for (;;) {
-+        pa_stream_state_t state;
-+
-+        state = pa_stream_get_state(p->stream);
-+
-+        if (state == PA_STREAM_READY)
-+            break;
-+
-+        if (!PA_STREAM_IS_GOOD(state)) {
-+            error = pa_context_errno(p->context);
-+            goto unlock_and_fail;
-+        }
-+
-+        /* Wait until the stream is ready */
-+        pa_threaded_mainloop_wait(p->mainloop);
-+    }
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+    return p;
-+
-+unlock_and_fail:
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+fail:
-+    if (rerror)
-+        *rerror = error;
-+    pa_simple_free(p);
-+    return NULL;
-+}
- void pa_simple_free(pa_simple *s) {
-     pa_assert(s);
-@@ -454,6 +580,111 @@ unlock_and_fail:
-     return -1;
- }
-+int pa_simple_mute(pa_simple *p, int mute, int *rerror) {
-+    pa_operation *o = NULL;
-+    uint32_t idx;
-+
-+    pa_assert(p);
-+
-+    CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+    CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+
-+    CHECK_SUCCESS_GOTO(p, rerror, ((idx = pa_stream_get_index (p->stream)) != PA_INVALID_INDEX), unlock_and_fail);
-+
-+
-+    o = pa_context_set_sink_input_mute (p->context, idx, mute, success_context_cb, p);
-+    CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
-+
-+    p->operation_success = 0;
-+    while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
-+        pa_threaded_mainloop_wait(p->mainloop);
-+        CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+    }
-+    CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
-+
-+    pa_operation_unref(o);
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+    return 0;
-+
-+unlock_and_fail:
-+
-+    if (o) {
-+        pa_operation_cancel(o);
-+        pa_operation_unref(o);
-+    }
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+    return -1;
-+}
-+
-+int pa_simple_get_stream_index(pa_simple *p, unsigned int *idx, int *rerror) {
-+    pa_assert(p);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, idx != NULL, PA_ERR_INVALID, -1);
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+
-+    CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+
-+      *idx = pa_stream_get_index(p->stream);
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+    return 0;
-+
-+unlock_and_fail:
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+    return -1;
-+}
-+
-+int pa_simple_set_volume(pa_simple *p, int volume, int *rerror) {
-+    pa_operation *o = NULL;
-+    pa_stream *s = NULL;
-+    uint32_t idx;
-+    pa_cvolume cv;
-+    pa_volume_t v;
-+
-+    pa_assert(p);
-+
-+    CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, volume >= 0, PA_ERR_INVALID, -1);
-+    CHECK_VALIDITY_RETURN_ANY(rerror, volume <= 65535, PA_ERR_INVALID, -1);
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+    CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+
-+    CHECK_SUCCESS_GOTO(p, rerror, ((idx = pa_stream_get_index (p->stream)) != PA_INVALID_INDEX), unlock_and_fail);
-+
-+    s = p->stream;
-+    pa_assert(s);
-+    pa_cvolume_set(&cv, s->sample_spec.channels, volume);
-+
-+    o = pa_context_set_sink_input_volume (p->context, idx, &cv, success_context_cb, p);
-+    CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
-+
-+    p->operation_success = 0;
-+    while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
-+        pa_threaded_mainloop_wait(p->mainloop);
-+        CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+    }
-+    CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
-+
-+    pa_operation_unref(o);
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+    return 0;
-+
-+unlock_and_fail:
-+
-+    if (o) {
-+        pa_operation_cancel(o);
-+        pa_operation_unref(o);
-+    }
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+    return -1;
-+}
- pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) {
-     pa_usec_t t;
-     int negative;
-@@ -483,3 +714,50 @@ unlock_and_fail:
-     pa_threaded_mainloop_unlock(p->mainloop);
-     return (pa_usec_t) -1;
- }
-+
-+int pa_simple_cork(pa_simple *p, int cork, int *rerror) {
-+    pa_operation *o = NULL;
-+
-+    pa_assert(p);
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+    CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+
-+    o = pa_stream_cork(p->stream, cork, success_context_cb, p);
-+    CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
-+
-+    p->operation_success = 0;
-+    while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
-+        pa_threaded_mainloop_wait(p->mainloop);
-+        CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
-+    }
-+    CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
-+
-+    pa_operation_unref(o);
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+    return 0;
-+
-+unlock_and_fail:
-+
-+    if (o) {
-+        pa_operation_cancel(o);
-+        pa_operation_unref(o);
-+    }
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+    return -1;
-+}
-+
-+int pa_simple_is_corked(pa_simple *p) {
-+      int is_cork;
-+    pa_assert(p);
-+
-+    pa_threaded_mainloop_lock(p->mainloop);
-+
-+    is_cork = pa_stream_is_corked(p->stream);
-+
-+    pa_threaded_mainloop_unlock(p->mainloop);
-+
-+    return is_cork;
-+}
-diff --git a/src/pulse/simple.h b/src/pulse/simple.h
-index 0fab8ee..bff9dbb 100644
---- a/src/pulse/simple.h
-+++ b/src/pulse/simple.h
-@@ -31,6 +31,7 @@
- #include <pulse/cdecl.h>
- #include <pulse/version.h>
-+#include <pulse/proplist.h>
- /** \page simple Simple API
-  *
-  * \section overv_sec Overview
-@@ -128,6 +129,19 @@ pa_simple* pa_simple_new(
-     int *error                          /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */
-     );
-+/** Create a new connection to the server with proplist */
-+pa_simple* pa_simple_new_proplist(
-+    const char *server,                 /**< Server name, or NULL for default */
-+    const char *name,                   /**< A descriptive name for this client (application name, ...) */
-+    pa_stream_direction_t dir,          /**< Open this stream for recording or playback? */
-+    const char *dev,                    /**< Sink (resp. source) name, or NULL for default */
-+    const char *stream_name,            /**< A descriptive name for this client (application name, song title, ...) */
-+    const pa_sample_spec *ss,           /**< The sample type to use */
-+    const pa_channel_map *map,          /**< The channel map to use, or NULL for default */
-+    const pa_buffer_attr *attr,         /**< Buffering attributes, or NULL for default */
-+    pa_proplist *proplist,    /**< Properties, or NULL for default */
-+    int *error                          /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */
-+    );
- /** Close and free the connection to the server. The connection object becomes invalid when this is called. */
- void pa_simple_free(pa_simple *s);
-@@ -145,6 +159,20 @@ pa_usec_t pa_simple_get_latency(pa_simple *s, int *error);
- /** Flush the playback buffer. This discards any audio in the buffer. */
- int pa_simple_flush(pa_simple *s, int *error);
-+/** Mute the playback stream */
-+int pa_simple_mute(pa_simple *p, int mute, int *rerror);
-+
-+/** Volume control the playback stream */
-+int pa_simple_set_volume(pa_simple *p, int volume, int *rerror);
-+
-+/** Get stream index */
-+int pa_simple_get_stream_index(pa_simple *p, unsigned int *idx, int *rerror);
-+
-+/** Cork on=1/off=0 stream */
-+int pa_simple_cork(pa_simple *p, int cork, int *rerror);
-+
-+/** Check whether stream is corked or not */
-+int pa_simple_is_corked(pa_simple *p);
- PA_C_DECL_END
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_git.bb_old b/recipes-multimedia/pulseaudio/pulseaudio_git.bb_old
deleted file mode 100644 (file)
index 55db501..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-require pulseaudio.inc
-
-PRIORITY = "10"
-
-S = "${WORKDIR}/git"
-
-LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
-
-SRC_URI = "git://review.tizen.org/platform/upstream/pulseaudio;tag=99714e130755179217cd948661eaca8d31e041c7;nobranch=1"
-
-#SRC_URI += "file://0001-configure.ac-Check-only-for-libsystemd-not-libsystem.patch"
-SRC_URI += "file://volatiles.04_pulse"
-
-
-BBCLASSEXTEND += " native "
-
-do_compile_prepend() {
-        ${S}/bootstrap.sh
-}
-
-do_compile_prepend() {
-    mkdir -p ${S}/libltdl
-    cp ${STAGING_LIBDIR}/libltdl* ${S}/libltdl
-}