summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKévin THIERRY <kevin.thierry@open.eurogiciel.org>2014-10-17 14:21:49 +0200
committerronan(Eurogiciel) Le Martret <ronan.lemartret@open.eurogiciel.org>2014-10-20 02:11:50 -0700
commit4e6fdd0aa7bc53eebe983083781b9aeefc783e11 (patch)
treeaae71bc58ecd00a9505bc24a42a7ef035018d1d3
parentac4a5dd7072cf26748f4b5410ba459b39c380971 (diff)
downloadmeta-tizen-4e6fdd0aa7bc53eebe983083781b9aeefc783e11.tar.gz
meta-tizen-4e6fdd0aa7bc53eebe983083781b9aeefc783e11.tar.bz2
meta-tizen-4e6fdd0aa7bc53eebe983083781b9aeefc783e11.zip
Remove old bbappend for pulseaudio
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>
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0.bbappend110
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0001-volume-ramp-additions-to-the-low-level-infra.patch559
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0002-volume-ramp-add-volume-ramping-to-sink.patch243
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0003-volume-ramp-adding-volume-ramping-to-sink-input.patch181
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0004-build-sys-install-files-for-a-module-development.patch72
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0005-jack-detection-fix-for-wired-headset.patch23
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0006-make-pa_thread_mq_done-safe-for-subsequent-calls.patch29
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0007-node-manager-adding-external-node-manager-API.patch568
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0008-node-manager-adding-node-support-for-pactl.patch152
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0009-add-internal-corking-state-for-sink-input.patch87
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0010-bluetooth-Add-basic-support-for-HEADSET-profiles.patch634
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0011-bluetooth-Create-Handsfree-Audio-Agent-NULL-backend.patch176
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0012-bluetooth-Create-Handsfree-Audio-Agent-oFono-backend.patch161
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0013-bluetooth-Monitor-D-Bus-signals.patch99
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0014-bluetooth-Create-pa_bluetooth_dbus_send_and_add_to_p.patch51
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0015-bluetooth-Register-Unregister-Handsfree-Audio-Agent-.patch172
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0016-bluetooth-List-HandsfreeAudioCard-objects-from-oFono.patch98
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0017-bluetooth-Parse-HandsfreeAudioCard-properties.patch192
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0018-bluetooth-Implement-transport-acquire-for-hf_audio_a.patch48
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0019-bluetooth-Track-oFono-service.patch109
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0020-bluetooth-Handle-CardAdded-signal.patch38
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0021-bluetooth-Handle-CardRemoved-signal.patch43
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0022-bluetooth-Implement-org.ofono.HandsfreeAudioAgent.Ne.patch56
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0023-bluetooth-Fix-not-handle-fd-in-DEFER_SETUP-state.patch44
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0024-bluetooth-Suspend-sink-source-on-HFP-s-stream-HUP.patch60
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0025-bluetooth-Implement-transport-release-for-hf_audio_a.patch27
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0026-bluetooth-Fixes-HFP-audio-transfer-when-initiator.patch59
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0027-bluetooth-Set-off-profile-as-default-for-newly-creat.patch37
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0028-fix-ofono-and-pulseaudio-starting-order-assert.patch27
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0029-hfp-do-safe-strcmp-in-dbus-handler.patch23
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0030-add-parameter-to-define-key-used-in-stream-restore.patch258
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0031-increase-alsa-rewind-safeguard.patch39
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0032-fix-for-profile-change-prototype-in-bluez5-patch.patch23
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0033-changes-to-pa-simple-api-samsung.patch438
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0034-add-support-for-samsung-power-management-samsung.patch301
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0035-Add-preload-fileter-for-resample-samsung.patch.gzbin112359 -> 0 bytes
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0036-Enhance-for-echo-cancel-samsung.patch304
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0037-add-support-for-dlog-samsung.patch285
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0038-add-policy-module-samsung.patch1317
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0039-add-bluetooth-a2dp-aptx-codec-support-samsung.patch1024
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0040-create-pa_ready-file-samsung.patch40
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0041-set-alsa-suspend-timeout-to-zero-samsung.patch32
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0042-cope-with-possible-infinite-waiting-in-startup-samsu.patch61
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0043-use-udev-only-for-usb-devices-samsung.patch98
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0044-fixes-and-improvements-to-makefile-and-configure-in-.patch120
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0045-fix-warning-in-gconf-helper.patch24
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0046-volume-ramp-add-client-api-support-for-volume-rampin.patch461
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0047-adjust-default-bluetooth-profile-to-off.patch23
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0048-Add-bt_profile_set-patch-which-fixed-bt-a2dp-hsp-pro.patch83
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0049-added-pulseaudio.service-file.patch27
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0050-.gitignore-Add-pulsecore-config.h.patch19
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0051-pactl-Fix-crash-with-older-servers.patch405
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0052-volume-Increase-PA_SW_VOLUME_SNPRINT_DB_MAX.patch26
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0053-sink-input-source-output-Fix-mute-saving.patch37
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0054-direction-Add-a-couple-of-direction-helper-functions.patch180
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0055-core-util-Add-pa_join.patch52
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0056-dynarray-Add-pa_dynarray_get_raw_array.patch36
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0057-dynarray-Add-PA_DYNARRAY_FOREACH.patch64
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0058-dynarray-Add-pa_dynarray_remove_last.patch51
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0059-dynarray-Add-pa_dynarray_remove_all.patch57
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0060-hashmap-Add-pa_hashmap_remove_and_free.patch53
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0061-device-port-Add-pa_device_port.active.patch236
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0062-sink-source-Assign-to-reference_volume-from-only-one.patch246
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0063-sink-input-source-output-Assign-to-volume-from-only-.patch506
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0064-sink-source-Return-early-from-set_mute.patch75
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0065-sink-input-source-output-Add-logging-to-set_mute.patch67
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0066-sink-source-Allow-calling-set_mute-during-initializa.patch61
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0067-echo-cancel-Remove-redundant-get_mute-callback.patch47
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0068-sink-source-Call-set_mute-from-mute_changed.patch133
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0069-sink-source-Assign-to-s-muted-from-only-one-place.patch346
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0070-sink-input-source-output-Remove-redundant-get_mute-f.patch210
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0071-solaris-tunnel-Remove-some-redundant-boolean-convers.patch37
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0072-sink-source-Add-hooks-for-volume-changes.patch52
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0073-sink-input-source-output-Add-hooks-for-volume-change.patch52
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0074-sink-source-Add-hooks-for-mute-changes.patch56
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0075-sink-input-source-output-Add-hooks-for-mute-changes.patch56
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0076-sink-Link-monitor-source-before-activating-port.patch30
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0077-context-extension-Add-the-pa_extension-class.patch338
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0078-volume-api-Add-libvolume-api.so.patch.gzbin27952 -> 0 bytes
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0079-Add-module-volume-api-and-the-related-client-API.patch.gzbin13036 -> 0 bytes
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0080-pactl-Add-support-for-the-new-volume-API.patch963
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0081-Add-module-audio-groups.patch1425
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0082-Add-module-main-volume-policy.patch1404
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0083-configuration-Add-default-IVI-audio-group-and-main-v.patch119
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0084-sink-source-Initialize-port-before-fixate-hook-fixes.patch159
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0085-configuration-pulseaudio-tizen-configuration-in-defa.patch123
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0086-pactl-Fix-crash-in-pactl-list.patch26
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0087-configuration-x-example-x-tizen-ivi-in-volume-config.patch173
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0088-device-creator-stream-creator-Add-a-couple-of-assert.patch47
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0089-main-volume-policy-Fix-a-memory-leak.patch64
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0090-audio-groups-fix-issues-found-by-static-analysis.patch146
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0091-core-util-Add-pa_append_to_home_dir.patch72
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0092-core-util-Add-pa_get_config_home_dir.patch116
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0093-core-util-Add-pa_append_to_config_home_dir.patch49
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0094-core-Create-the-config-home-directory-on-startup.patch55
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0095-alsa-Handle-unlinking-of-uninitialized-streams-grace.patch42
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0096-role-cork-Handle-unlinking-of-uninitialized-streams-.patch26
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0097-role-ducking-Handle-unlinking-of-uninitialized-strea.patch26
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0098-core-util-Add-pa_boolean_to_string.patch28
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0099-sink-input-source-output-Assign-to-reference_ratio-f.patch243
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0100-sink-input-source-output-Add-hooks-for-reference-rat.patch87
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0101-sink-input-source-output-Use-new_data.volume-only-fo.patch411
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0102-sink-input-source-output-Add-the-real-object-pointer.patch543
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/0103-audio-groups-main-volume-policy-volume-api-Various-f.patch9676
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/change_libsystemd_to_libsystemd-login_in_configure.patch11
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_5.0/changes-to-pa-simple-api-samsung.patch426
-rw-r--r--recipes-multimedia/pulseaudio/pulseaudio_git.bb_old24
107 files changed, 0 insertions, 29148 deletions
diff --git a/recipes-multimedia/pulseaudio/pulseaudio_5.0.bbappend b/recipes-multimedia/pulseaudio/pulseaudio_5.0.bbappend
deleted file mode 100644
index 9258eb36..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0.bbappend
+++ /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
index 8b2693c6..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0001-volume-ramp-additions-to-the-low-level-infra.patch
+++ /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
index 4ea7c205..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0002-volume-ramp-add-volume-ramping-to-sink.patch
+++ /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
index 9557dc85..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0003-volume-ramp-adding-volume-ramping-to-sink-input.patch
+++ /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
index 8b43385e..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0004-build-sys-install-files-for-a-module-development.patch
+++ /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
index 002e4ec7..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0005-jack-detection-fix-for-wired-headset.patch
+++ /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
index bfbf3d92..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0006-make-pa_thread_mq_done-safe-for-subsequent-calls.patch
+++ /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
index 5deba2be..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0007-node-manager-adding-external-node-manager-API.patch
+++ /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
index 64cc9c3d..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0008-node-manager-adding-node-support-for-pactl.patch
+++ /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
index 3ff665d3..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0009-add-internal-corking-state-for-sink-input.patch
+++ /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
index 3249f6ff..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0010-bluetooth-Add-basic-support-for-HEADSET-profiles.patch
+++ /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
index 0ead373f..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0011-bluetooth-Create-Handsfree-Audio-Agent-NULL-backend.patch
+++ /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
index 39b938b4..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0012-bluetooth-Create-Handsfree-Audio-Agent-oFono-backend.patch
+++ /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
index 0a93d5c3..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0013-bluetooth-Monitor-D-Bus-signals.patch
+++ /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
index c9d893cd..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0014-bluetooth-Create-pa_bluetooth_dbus_send_and_add_to_p.patch
+++ /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
index 931069c1..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0015-bluetooth-Register-Unregister-Handsfree-Audio-Agent-.patch
+++ /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
index d943ce47..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0016-bluetooth-List-HandsfreeAudioCard-objects-from-oFono.patch
+++ /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
index f7a2174a..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0017-bluetooth-Parse-HandsfreeAudioCard-properties.patch
+++ /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
index c3815cca..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0018-bluetooth-Implement-transport-acquire-for-hf_audio_a.patch
+++ /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
index 5f8fa213..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0019-bluetooth-Track-oFono-service.patch
+++ /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
index f3aaf335..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0020-bluetooth-Handle-CardAdded-signal.patch
+++ /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
index fbd766e2..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0021-bluetooth-Handle-CardRemoved-signal.patch
+++ /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
index 4ad62dcf..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0022-bluetooth-Implement-org.ofono.HandsfreeAudioAgent.Ne.patch
+++ /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
index 587fce66..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0023-bluetooth-Fix-not-handle-fd-in-DEFER_SETUP-state.patch
+++ /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
index 5858d67e..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0024-bluetooth-Suspend-sink-source-on-HFP-s-stream-HUP.patch
+++ /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
index b557ea5d..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0025-bluetooth-Implement-transport-release-for-hf_audio_a.patch
+++ /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
index 4dd9742d..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0026-bluetooth-Fixes-HFP-audio-transfer-when-initiator.patch
+++ /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
index cce04971..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0027-bluetooth-Set-off-profile-as-default-for-newly-creat.patch
+++ /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
index db44a2eb..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0028-fix-ofono-and-pulseaudio-starting-order-assert.patch
+++ /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
index 8402ffa8..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0029-hfp-do-safe-strcmp-in-dbus-handler.patch
+++ /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
index 0773d406..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0030-add-parameter-to-define-key-used-in-stream-restore.patch
+++ /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
index eac18110..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0031-increase-alsa-rewind-safeguard.patch
+++ /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
index 646694a0..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0032-fix-for-profile-change-prototype-in-bluez5-patch.patch
+++ /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
index e041892e..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0033-changes-to-pa-simple-api-samsung.patch
+++ /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
index 5d2380b4..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0034-add-support-for-samsung-power-management-samsung.patch
+++ /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
index a8f29d72..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0035-Add-preload-fileter-for-resample-samsung.patch.gz
+++ /dev/null
Binary files 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
index 19bbb16b..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0036-Enhance-for-echo-cancel-samsung.patch
+++ /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
index 33c38c35..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0037-add-support-for-dlog-samsung.patch
+++ /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
index fb976b19..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0038-add-policy-module-samsung.patch
+++ /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
index 13550480..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0039-add-bluetooth-a2dp-aptx-codec-support-samsung.patch
+++ /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
index 191e70e5..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0040-create-pa_ready-file-samsung.patch
+++ /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
index 9c6c9a42..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0041-set-alsa-suspend-timeout-to-zero-samsung.patch
+++ /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
index 4e91da47..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0042-cope-with-possible-infinite-waiting-in-startup-samsu.patch
+++ /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
index d989b3f3..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0043-use-udev-only-for-usb-devices-samsung.patch
+++ /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
index 0cb735ba..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0044-fixes-and-improvements-to-makefile-and-configure-in-.patch
+++ /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
index b89ec5ad..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0045-fix-warning-in-gconf-helper.patch
+++ /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
index 9cc07b69..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0046-volume-ramp-add-client-api-support-for-volume-rampin.patch
+++ /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
index 4f20de20..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0047-adjust-default-bluetooth-profile-to-off.patch
+++ /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
index 83227f7f..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0048-Add-bt_profile_set-patch-which-fixed-bt-a2dp-hsp-pro.patch
+++ /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
index c4c125ca..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0049-added-pulseaudio.service-file.patch
+++ /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
index c5c1d3bd..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0050-.gitignore-Add-pulsecore-config.h.patch
+++ /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
index cd4736c0..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0051-pactl-Fix-crash-with-older-servers.patch
+++ /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
index 32330d69..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0052-volume-Increase-PA_SW_VOLUME_SNPRINT_DB_MAX.patch
+++ /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
index fc389f64..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0053-sink-input-source-output-Fix-mute-saving.patch
+++ /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
index 32825969..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0054-direction-Add-a-couple-of-direction-helper-functions.patch
+++ /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
index d510f449..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0055-core-util-Add-pa_join.patch
+++ /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
index cf2c6946..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0056-dynarray-Add-pa_dynarray_get_raw_array.patch
+++ /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
index 64d8ce5c..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0057-dynarray-Add-PA_DYNARRAY_FOREACH.patch
+++ /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
index a6e0f566..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0058-dynarray-Add-pa_dynarray_remove_last.patch
+++ /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
index d2e66b51..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0059-dynarray-Add-pa_dynarray_remove_all.patch
+++ /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
index 09ab1084..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0060-hashmap-Add-pa_hashmap_remove_and_free.patch
+++ /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
index ef71747e..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0061-device-port-Add-pa_device_port.active.patch
+++ /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
index 2f5a35c6..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0062-sink-source-Assign-to-reference_volume-from-only-one.patch
+++ /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
index 38b32933..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0063-sink-input-source-output-Assign-to-volume-from-only-.patch
+++ /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
index 4cd0fdbf..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0064-sink-source-Return-early-from-set_mute.patch
+++ /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
index a60d1d28..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0065-sink-input-source-output-Add-logging-to-set_mute.patch
+++ /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
index 02ac7b5e..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0066-sink-source-Allow-calling-set_mute-during-initializa.patch
+++ /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
index 4962b8d0..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0067-echo-cancel-Remove-redundant-get_mute-callback.patch
+++ /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
index 42422ead..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0068-sink-source-Call-set_mute-from-mute_changed.patch
+++ /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
index c7332fd6..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0069-sink-source-Assign-to-s-muted-from-only-one-place.patch
+++ /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
index 9b25a3d7..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0070-sink-input-source-output-Remove-redundant-get_mute-f.patch
+++ /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
index 4b4acfec..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0071-solaris-tunnel-Remove-some-redundant-boolean-convers.patch
+++ /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
index 08fbc830..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0072-sink-source-Add-hooks-for-volume-changes.patch
+++ /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
index 9cf1c672..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0073-sink-input-source-output-Add-hooks-for-volume-change.patch
+++ /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
index ddd85146..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0074-sink-source-Add-hooks-for-mute-changes.patch
+++ /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
index 2607c140..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0075-sink-input-source-output-Add-hooks-for-mute-changes.patch
+++ /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
index e2de6d64..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0076-sink-Link-monitor-source-before-activating-port.patch
+++ /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
index a2a51417..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0077-context-extension-Add-the-pa_extension-class.patch
+++ /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
index 465ef386..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0078-volume-api-Add-libvolume-api.so.patch.gz
+++ /dev/null
Binary files 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
index d3e3ee7b..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0079-Add-module-volume-api-and-the-related-client-API.patch.gz
+++ /dev/null
Binary files 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
index 3fd8311b..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0080-pactl-Add-support-for-the-new-volume-API.patch
+++ /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
index b918bffd..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0081-Add-module-audio-groups.patch
+++ /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
index 52fd3ab0..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0082-Add-module-main-volume-policy.patch
+++ /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
index 5eed75c0..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0083-configuration-Add-default-IVI-audio-group-and-main-v.patch
+++ /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
index 37b4f858..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0084-sink-source-Initialize-port-before-fixate-hook-fixes.patch
+++ /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
index 8a279907..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0085-configuration-pulseaudio-tizen-configuration-in-defa.patch
+++ /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
index e8176841..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0086-pactl-Fix-crash-in-pactl-list.patch
+++ /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
index 2882e563..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0087-configuration-x-example-x-tizen-ivi-in-volume-config.patch
+++ /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
index a637c29f..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0088-device-creator-stream-creator-Add-a-couple-of-assert.patch
+++ /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
index 8c46a1b7..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0089-main-volume-policy-Fix-a-memory-leak.patch
+++ /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
index 52bfd207..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0090-audio-groups-fix-issues-found-by-static-analysis.patch
+++ /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
index 89732c8f..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0091-core-util-Add-pa_append_to_home_dir.patch
+++ /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
index e5e05e12..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0092-core-util-Add-pa_get_config_home_dir.patch
+++ /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
index da7a6ef7..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0093-core-util-Add-pa_append_to_config_home_dir.patch
+++ /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
index 2d86fde3..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0094-core-Create-the-config-home-directory-on-startup.patch
+++ /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
index 54b65301..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0095-alsa-Handle-unlinking-of-uninitialized-streams-grace.patch
+++ /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
index 0bd88211..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0096-role-cork-Handle-unlinking-of-uninitialized-streams-.patch
+++ /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
index 0f3d20a3..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0097-role-ducking-Handle-unlinking-of-uninitialized-strea.patch
+++ /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
index ad48a217..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0098-core-util-Add-pa_boolean_to_string.patch
+++ /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
index d8c815aa..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0099-sink-input-source-output-Assign-to-reference_ratio-f.patch
+++ /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
index cfbfdde4..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0100-sink-input-source-output-Add-hooks-for-reference-rat.patch
+++ /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
index 13d52213..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0101-sink-input-source-output-Use-new_data.volume-only-fo.patch
+++ /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
index 35b67f5d..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0102-sink-input-source-output-Add-the-real-object-pointer.patch
+++ /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
index 626d911e..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/0103-audio-groups-main-volume-policy-volume-api-Various-f.patch
+++ /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
index d65cc743..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/change_libsystemd_to_libsystemd-login_in_configure.patch
+++ /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
index a39ae06c..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_5.0/changes-to-pa-simple-api-samsung.patch
+++ /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
index 55db5013..00000000
--- a/recipes-multimedia/pulseaudio/pulseaudio_git.bb_old
+++ /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
-}