Hello community,

here is the log from the commit of package pulseaudio.3719 for 
openSUSE:13.2:Update checked in at 2015-04-23 08:39:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:13.2:Update/pulseaudio.3719 (Old)
 and      /work/SRC/openSUSE:13.2:Update/.pulseaudio.3719.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "pulseaudio.3719"

Changes:
--------
New Changes file:

--- /dev/null   2015-03-12 01:14:30.992027505 +0100
+++ /work/SRC/openSUSE:13.2:Update/.pulseaudio.3719.new/pulseaudio.changes      
2015-04-23 08:39:53.000000000 +0200
@@ -0,0 +1,1143 @@
+-------------------------------------------------------------------
+Tue Apr 21 17:15:47 CEST 2015 - ti...@suse.de
+
+- Fix crash by device switching (bnc#928035):
+  0038-sink-input-source-output-Fix-mute-saving.patch
+  0039-sink-source-Return-early-from-set_mute.patch
+  0040-sink-source-Allow-calling-set_mute-during-initializa.patch
+
+-------------------------------------------------------------------
+Mon Feb 23 17:18:53 CET 2015 - ti...@suse.de
+
+- Backport ALSA module fixes from PA 6.0 (bnc#906138, bnc#908288,
+  bnc#910983, bnc#911615, bnc#913686, bnc#916048):
+  0002-alsa-mixer-Fix-Analog-Input-showing-up-on-USB-Headse.patch
+  0003-alsa-Use-card-description-in-default-sink-source-pre.patch
+  0004-alsa-util-Reset-hwparams_copy-before-the-second-try-.patch
+  0005-Name-HDMI-outputs-uniquely.patch
+  0007-sink-source-Assign-to-s-muted-from-only-one-place.patch
+  0008-alsa-mixer-Add-surround-2.1-profile.patch
+  0009-alsa-Add-extra-HDMI-mappings.patch
+  0010-alsa-Add-exact-channels-mapping-configurability.patch
+  0011-alsa-Allow-fallback-configuration-for-mappings-and-p.patch
+  0012-alsa-Add-a-multichannel-fallback-mapping.patch
+  0013-alsa-mixer-Fix-path-subset-detection.patch
+  0014-alsa-Remove-four-channel-input-profile.patch
+  0015-alsa-mixer-Mark-Line-HP-Swap-as-required-any.patch
+  0017-alsa-mixer-recognize-Dock-headphone-jack.patch
+  0018-alsa-util-Add-functions-for-accessing-mixer-elements.patch
+  0019-alsa-mixer-card-Move-to-use-the-new-mixer-interface.patch
+  0020-alsa-Remove-unnecessary-hctl-handles-being-passed-ar.patch
+  0021-alsa-mixer-Merge-analog-output-desktop-speaker-with-.patch
+  0024-alsa-mixer-Ignore-some-elements-in-the-analog-output.patch
+  0025-alsa-mixer-Disable-line-out-if-headphone-jack-is-plu.patch
+  0026-alsa-mixer-Add-support-for-Headphone-LO-and-Speaker-.patch
+  0029-Alsa-Correct-port-availability-with-multiple-jacks.patch
+  0032-alsa-util-fix-parenthesis-position-in-err-assignment.patch
+  0033-alsa-mixer-Mute-headphones-and-speakers-on-line-out-.patch
+  0035-alsa-mixer-Add-lineout-to-surround21-mappings.patch
+  0036-alsa-mixer-Make-speaker-unavailable-when-Line-Out-is.patch
+  0037-alsa-Don-t-try-to-use-ELD-controls-with-UCM.patch
+- Drop stray alsa-mixer-recognize-Dock-headphone-jack.patch
+
+-------------------------------------------------------------------
+Mon Nov 17 22:38:54 CET 2014 - ti...@suse.de
+
+- Remove a patch causing more regressions, lost headphone handling
+  on Thinkpads (bnc#905418):
+  0002-alsa-mixer-Ignore-some-elements-in-the-analog-output.patch
+
+-------------------------------------------------------------------
+Wed Nov 12 12:53:49 CET 2014 - ti...@suse.de
+
+- Fix setup-pulseaudio script not to leave $ALSA_CONFIG_PATH when
+  alsa-plugins-pulse isn't installed (bnc#905055)
+
+-------------------------------------------------------------------
+Wed Nov  5 14:49:17 CET 2014 - ti...@suse.de
+
+- Fix wrong mixer setup / jack detection issues (bnc#851362)
+  0001-alsa-mixer-recognize-Dock-headphone-jack.patch
+  0002-alsa-mixer-Ignore-some-elements-in-the-analog-output.patch
+
+-------------------------------------------------------------------
+Sat Oct 18 20:29:58 UTC 2014 - crrodrig...@opensuse.org
+
+- Replace xorg-x11-devel for the exact pkgconfig deps needed.
+- Tell doxygen not to generate timestamped html docs.
+
+-------------------------------------------------------------------
+Tue Sep 16 08:48:44 UTC 2014 - mplus...@suse.com
+
+- Add user pulse to audio group - see bnc#896846
+
+-------------------------------------------------------------------
+Fri Jul 18 20:11:16 UTC 2014 - sree...@suse.com
+
+- Add pulseaudio-bnc881524-rtp.patch.  CVE-2014-3970
+    Denial of service in module-rtp-recv
+
+-------------------------------------------------------------------
+Thu Mar 20 20:17:16 UTC 2014 - crrodrig...@opensuse.org
+
+-  build: do not depend on tcpd-devel which is unmaintained
+- pulseaudio.service: Use the new journal log target.
+
+-------------------------------------------------------------------
+Mon Mar  3 16:32:10 UTC 2014 - ohole...@suse.com
+
+- Update to 5.0 final
+  + BlueZ 5 support (A2DP only)
+  + Reimplementation of the tunnel modules
+  + Native log target support for systemd-journal
+  + Many bug fixes
+- Remove pulseaudio-revert-protocol-native.patch, included upstream
+- Lower required alsa-lib version to 1.0.19
+  (stated in notes for packagers)
+
+-------------------------------------------------------------------
+Wed Feb 26 10:21:23 UTC 2014 - seife+...@b1-systems.com
+
+- relax the bluez dependency of pulseaudio-module-bluetooth from
+  == bluez_version to >= bluez_version so that newer 3rd-party
+  bluez builds (my testing builds e.g. :-) can be used
+
+-------------------------------------------------------------------
+Sun Feb 23 19:01:59 UTC 2014 - zai...@opensuse.org
+
+- Update to version 4.99.4:
+  + sink-input, source-output: Don't crash if format negotiation
+    fails.
+  + man:
+    - pulse-cli-syntax: Document the "journal" log target.
+    - Improve man page and help for cmdline options.
+  + dbus: Use correct idxset when getting sources.
+  + source: Increase max outputs per source
+  + protocol-native: Fix a crash
+  + thread-win32: Implement pa_thread_free_nojoin()
+  + Updated translations.
+- Add pulseaudio-revert-protocol-native.patch: Don't enumerate
+  unlinked sinks and sources".
+
+-------------------------------------------------------------------
+Thu Jan 30 09:53:30 UTC 2014 - ohole...@suse.cz
+
+- update to version 5.0 RC3 (4.99.3)
+- reenable orc
+
+-------------------------------------------------------------------
+Thu Jan 23 20:54:47 UTC 2014 - dims...@opensuse.org
+
+- Update to version 5.0 RC2 (4.99.2):
+  + This is finally an officially released tarball on the road to
+    pulseaudio 5.0.
+- Drop pulseaudio-introspect-Fix-ABI-break.patch: fixed upstream.
+- Bump drvver to 4.99, following upstream.
+- Pass --disable-orc to configure in order to avoid build failures
+  due to orc files missing from the tarball.
+- Drop call to autogen.sh: no longer required, as we are building a
+  bootstrapped tarball.
+
+-------------------------------------------------------------------
+Mon Nov 25 11:20:40 CET 2013 - ti...@suse.de
+
+- pulseaudio-introspect-Fix-ABI-break.patch:
+  Fix the incompatible size of pa_card_profile_info that leads to
+  a crash of pavucontrol (bnc#851872)
+
+-------------------------------------------------------------------
+Sun Oct 20 20:52:41 UTC 2013 - ohole...@suse.com
+
+- enable bluez4 support for older openSUSE releases
+
+-------------------------------------------------------------------
+Fri Oct 18 17:49:24 UTC 2013 - dims...@opensuse.org
+
+- Update to git master (PA 5.0) (4.0-270-g9490a):
+  + alsa: fix crash when loading bare alsa sink (bnc#846532).
+  + sndfile-util: fir format for 24bit depth wav files.
+  + bluetooth: track discovery modules by index.
+  + build system fixes.
+
+-------------------------------------------------------------------
+Sat Oct  5 23:37:59 UTC 2013 - dims...@opensuse.org
+
+- Update to git mastere (PA 5.0 on the way) (265-g35fe):
+  + The more extensive bluez5 branch was merged
+  + PA allows to build bluez4 and bluez5 modules in parallel.
+    Note: this does not mean that bluez4 and bluez5 can co-exist,
+    only that PA can decide at runtime which bluez-daemon is
+    available.
+- Pass --disable-bluez4 to configure: we know that we run bluez5.
+
+-------------------------------------------------------------------
+Wed Sep 25 17:48:30 UTC 2013 - dims...@opensuse.org
+
+- bnc#840845: Update to git master (PA 5.0 on the way) (6f94c).
+  + Various code cleanups for inclusion of bluez5 stack.
+- No longer pass --enable-bluez5 --disable-bluez4 to configure:
+  master only speaks bluez5.
+
+-------------------------------------------------------------------
+Wed Sep 11 10:34:33 CEST 2013 - mhruse...@suse.cz
+
+- support for system wide mode (separate subpackage with service)
+
+-------------------------------------------------------------------
+Sat Sep  7 11:30:40 UTC 2013 - dims...@opensuse.org
+
+- Update to git snapshot (rev: gbf9b3)/ bluez5 branch.
+  Note: this is not HEAD of the bluez5 branch, as in local tests,
+  this did fail to load the bluetooth modules.
+
+-------------------------------------------------------------------
+Wed Aug 21 09:38:49 UTC 2013 - dims...@opensuse.org
+
+- Fix fdupes call on doxygen/html: use hardlinks instead of
+  softlinks (bnc#835683).
++++ 946 more lines (skipped)
++++ between /dev/null
++++ and /work/SRC/openSUSE:13.2:Update/.pulseaudio.3719.new/pulseaudio.changes

New:
----
  0002-alsa-mixer-Fix-Analog-Input-showing-up-on-USB-Headse.patch
  0003-alsa-Use-card-description-in-default-sink-source-pre.patch
  0004-alsa-util-Reset-hwparams_copy-before-the-second-try-.patch
  0005-Name-HDMI-outputs-uniquely.patch
  0007-sink-source-Assign-to-s-muted-from-only-one-place.patch
  0008-alsa-mixer-Add-surround-2.1-profile.patch
  0009-alsa-Add-extra-HDMI-mappings.patch
  0010-alsa-Add-exact-channels-mapping-configurability.patch
  0011-alsa-Allow-fallback-configuration-for-mappings-and-p.patch
  0012-alsa-Add-a-multichannel-fallback-mapping.patch
  0013-alsa-mixer-Fix-path-subset-detection.patch
  0014-alsa-Remove-four-channel-input-profile.patch
  0015-alsa-mixer-Mark-Line-HP-Swap-as-required-any.patch
  0017-alsa-mixer-recognize-Dock-headphone-jack.patch
  0018-alsa-util-Add-functions-for-accessing-mixer-elements.patch
  0019-alsa-mixer-card-Move-to-use-the-new-mixer-interface.patch
  0020-alsa-Remove-unnecessary-hctl-handles-being-passed-ar.patch
  0021-alsa-mixer-Merge-analog-output-desktop-speaker-with-.patch
  0024-alsa-mixer-Ignore-some-elements-in-the-analog-output.patch
  0025-alsa-mixer-Disable-line-out-if-headphone-jack-is-plu.patch
  0026-alsa-mixer-Add-support-for-Headphone-LO-and-Speaker-.patch
  0029-Alsa-Correct-port-availability-with-multiple-jacks.patch
  0032-alsa-util-fix-parenthesis-position-in-err-assignment.patch
  0033-alsa-mixer-Mute-headphones-and-speakers-on-line-out-.patch
  0035-alsa-mixer-Add-lineout-to-surround21-mappings.patch
  0036-alsa-mixer-Make-speaker-unavailable-when-Line-Out-is.patch
  0037-alsa-Don-t-try-to-use-ELD-controls-with-UCM.patch
  0038-sink-input-source-output-Fix-mute-saving.patch
  0039-sink-source-Return-early-from-set_mute.patch
  0040-sink-source-Allow-calling-set_mute-during-initializa.patch
  baselibs.conf
  default.pa-for-gdm
  disabled-start.diff
  pulseaudio-5.0.tar.xz
  pulseaudio-bnc881524-rtp.patch
  pulseaudio-server.fw
  pulseaudio-wrong-memset.patch
  pulseaudio.changes
  pulseaudio.service
  pulseaudio.spec
  setup-pulseaudio
  suppress-socket-error-msg.diff
  sysconfig.sound-pulseaudio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ pulseaudio.spec ++++++
++++ 697 lines (skipped)

++++++ 0002-alsa-mixer-Fix-Analog-Input-showing-up-on-USB-Headse.patch ++++++
>From 00922f7dc0b6b63325193b58721c2e910b7d4489 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Tue, 11 Mar 2014 05:50:10 +0100
Subject: [PATCH] alsa-mixer: Fix Analog Input showing up on USB Headset

In some cases, "Analog Input" could show up as well as
"Headset Mic" (or "Headphone Mic"), because I forgot to add the
relevant "required-absent" lines when I added the headset mic path.

As a result, both "Analog Input" and "Headset Mic" showed up on the
Logitech USB 530 Headset.

Reported-by: Steve Magoun <steve.mag...@canonical.com>
Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/mixer/paths/analog-input.conf |   15 +++++++++++++++
 1 file changed, 15 insertions(+)

--- a/src/modules/alsa/mixer/paths/analog-input.conf
+++ b/src/modules/alsa/mixer/paths/analog-input.conf
@@ -61,6 +61,21 @@ required-absent = any
 [Element Rear Mic Boost]
 required-absent = any
 
+[Element Headset]
+required-absent = any
+
+[Element Headset Mic]
+required-absent = any
+
+[Element Headset Mic Boost]
+required-absent = any
+
+[Element Headphone Mic]
+required-absent = any
+
+[Element Headphone Mic Boost]
+required-absent = any
+
 [Element Line]
 required-absent = any
 
++++++ 0003-alsa-Use-card-description-in-default-sink-source-pre.patch ++++++
>From fe6e41d7d27790338eb57073e42bfa8776112dd0 Mon Sep 17 00:00:00 2001
From: Pete Beardmore <pete.beardm...@msn.com>
Date: Thu, 13 Mar 2014 10:14:40 +0000
Subject: [PATCH] alsa: Use card description in default sink/source prefix when
 available

When given an explicit device.description in card_properties, prefer
this information over other default prefixes (e.g. 'Built-in Audio')
when constructing sink/source descriptions.

For example, if I manually configure the card description to be
"FooBar", I then expect that the sinks and created by the card also
have "FooBar" in their description instead of generic "Built-in
Audio".
---
 src/modules/alsa/alsa-sink.c        |    2 +-
 src/modules/alsa/alsa-source.c      |    2 +-
 src/modules/alsa/alsa-util.c        |    4 ++--
 src/modules/alsa/alsa-util.h        |    2 +-
 src/modules/alsa/module-alsa-card.c |    2 +-
 src/pulsecore/card.c                |    2 +-
 src/pulsecore/sink.c                |   15 ++++++++++-----
 src/pulsecore/sink.h                |    2 +-
 src/pulsecore/source.c              |    2 +-
 9 files changed, 19 insertions(+), 14 deletions(-)

--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -2278,7 +2278,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m,
             pa_proplist_sets(data.proplist, key, 
pa_proplist_gets(mapping->proplist, key));
     }
 
-    pa_alsa_init_description(data.proplist);
+    pa_alsa_init_description(data.proplist, card);
 
     if (u->control_device)
         pa_alsa_init_proplist_ctl(data.proplist, u->control_device);
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1984,7 +1984,7 @@ pa_source *pa_alsa_source_new(pa_module
             pa_proplist_sets(data.proplist, key, 
pa_proplist_gets(mapping->proplist, key));
     }
 
-    pa_alsa_init_description(data.proplist);
+    pa_alsa_init_description(data.proplist, card);
 
     if (u->control_device)
         pa_alsa_init_proplist_ctl(data.proplist, u->control_device);
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -868,11 +868,11 @@ void pa_alsa_refcnt_dec(void) {
     }
 }
 
-bool pa_alsa_init_description(pa_proplist *p) {
+bool pa_alsa_init_description(pa_proplist *p, pa_card *card) {
     const char *d, *k;
     pa_assert(p);
 
-    if (pa_device_init_description(p))
+    if (pa_device_init_description(p, card))
         return true;
 
     if (!(d = pa_proplist_gets(p, "alsa.card_name")))
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -118,7 +118,7 @@ void pa_alsa_init_proplist_pcm_info(pa_c
 void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card);
 void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm);
 void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name);
-bool pa_alsa_init_description(pa_proplist *p);
+bool pa_alsa_init_description(pa_proplist *p, pa_card *card);
 
 int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents);
 
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -704,7 +704,7 @@ int pa__init(pa_module *m) {
     pa_alsa_init_proplist_card(m->core, data.proplist, u->alsa_card_index);
 
     pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_id);
-    pa_alsa_init_description(data.proplist);
+    pa_alsa_init_description(data.proplist, NULL);
     set_card_name(&data, u->modargs, u->device_id);
 
     /* We need to give pa_modargs_get_value_boolean() a pointer to a local
--- a/src/pulsecore/card.c
+++ b/src/pulsecore/card.c
@@ -201,7 +201,7 @@ pa_card *pa_card_new(pa_core *core, pa_c
     c->userdata = NULL;
     c->set_profile = NULL;
 
-    pa_device_init_description(c->proplist);
+    pa_device_init_description(c->proplist, c);
     pa_device_init_icon(c->proplist, true);
     pa_device_init_intended_roles(c->proplist);
 
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -231,7 +231,7 @@ pa_sink* pa_sink_new(
     if (data->card)
         pa_proplist_update(data->proplist, PA_UPDATE_MERGE, 
data->card->proplist);
 
-    pa_device_init_description(data->proplist);
+    pa_device_init_description(data->proplist, data->card);
     pa_device_init_icon(data->proplist, true);
     pa_device_init_intended_roles(data->proplist);
 
@@ -3441,16 +3441,21 @@ bool pa_device_init_icon(pa_proplist *p,
     return true;
 }
 
-bool pa_device_init_description(pa_proplist *p) {
+bool pa_device_init_description(pa_proplist *p, pa_card *card) {
     const char *s, *d = NULL, *k;
     pa_assert(p);
 
     if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
         return true;
 
-    if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
-        if (pa_streq(s, "internal"))
-            d = _("Built-in Audio");
+    if (card)
+        if ((s = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_DESCRIPTION)))
+            d = s;
+
+    if (!d)
+        if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
+            if (pa_streq(s, "internal"))
+                d = _("Built-in Audio");
 
     if (!d)
         if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -399,7 +399,7 @@ void pa_sink_mute_changed(pa_sink *s, bo
 
 void pa_sink_update_flags(pa_sink *s, pa_sink_flags_t mask, pa_sink_flags_t 
value);
 
-bool pa_device_init_description(pa_proplist *p);
+bool pa_device_init_description(pa_proplist *p, pa_card *card);
 bool pa_device_init_icon(pa_proplist *p, bool is_sink);
 bool pa_device_init_intended_roles(pa_proplist *p);
 unsigned pa_device_init_priority(pa_proplist *p);
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -218,7 +218,7 @@ pa_source* pa_source_new(
     if (data->card)
         pa_proplist_update(data->proplist, PA_UPDATE_MERGE, 
data->card->proplist);
 
-    pa_device_init_description(data->proplist);
+    pa_device_init_description(data->proplist, data->card);
     pa_device_init_icon(data->proplist, false);
     pa_device_init_intended_roles(data->proplist);
 
++++++ 0004-alsa-util-Reset-hwparams_copy-before-the-second-try-.patch ++++++
>From 3c73e2130fd65e147c487b0b84c1a8b6a8afa04c Mon Sep 17 00:00:00 2001
From: Peter Ujfalusi <peter.ujfal...@ti.com>
Date: Fri, 21 Mar 2014 09:18:40 +0200
Subject: [PATCH] alsa-util: Reset hwparams_copy before the second try of
 buffer setup

hwparams_copy needs to be reset (as it is also reset for the third and
fourth try) before the second try.

If the reset is not done and the first try fails:
D: [lt-pulseaudio] alsa-util.c: Maximum hw buffer size is 743 ms
I: [lt-pulseaudio] alsa-util.c: snd_pcm_hw_params_set_buffer_size_near() 
failed: Invalid argument
I: [lt-pulseaudio] alsa-util.c: snd_pcm_hw_params_set_period_size_near() 
failed: Invalid argument
I: [lt-pulseaudio] alsa-util.c: snd_pcm_hw_params_set_buffer_size_near() 
failed: Invalid argument
D: [lt-pulseaudio] alsa-util.c: Set only period size (to 1102 samples).

We have three failures and finally the fourth (only period size) succeed.

With this patch:
D: [lt-pulseaudio] alsa-util.c: Maximum hw buffer size is 743 ms
I: [lt-pulseaudio] alsa-util.c: snd_pcm_hw_params_set_buffer_size_near() 
failed: Invalid argument
D: [lt-pulseaudio] alsa-util.c: Set period size first (to 1102 samples), buffer 
size second (to 4408 samples).

We only fail with the first try, the second (period followed by buffer) is
fine.

Signed-off-by: Peter Ujfalusi <peter.ujfal...@ti.com>
---
 src/modules/alsa/alsa-util.c |    1 +
 1 file changed, 1 insertion(+)

--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -327,6 +327,7 @@ int pa_alsa_set_hw_params(
                 goto success;
             }
 
+            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
             /* Second try: set period size first, followed by buffer size */
             if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 
&&
                 set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 
&&
++++++ 0005-Name-HDMI-outputs-uniquely.patch ++++++
>From a5ba31bf9627b6c7d7f5e03cdccff2d52fa3299d Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patra...@gmail.com>
Date: Thu, 10 Apr 2014 21:13:43 +0600
Subject: [PATCH] Name HDMI outputs uniquely

On Haswell hardware, there are multiple HDMI outputs capable of
digital sound output. As they were identically named, KDE's control
center was unable to distinguish them, restored the wrong profile and
thus routed sound to the wrong HDMI monitor.

Also, having identically-named menu items in other mixer applications
looks like a bug.
---
 src/modules/alsa/mixer/profile-sets/extra-hdmi.conf |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

--- a/src/modules/alsa/mixer/profile-sets/extra-hdmi.conf
+++ b/src/modules/alsa/mixer/profile-sets/extra-hdmi.conf
@@ -116,7 +116,7 @@ priority = 3
 direction = output
 
 [Mapping hdmi-stereo-extra1]
-description = Digital Stereo (HDMI)
+description = Digital Stereo (HDMI 2)
 device-strings = hdmi:%f,1
 paths-output = hdmi-output-1
 channel-map = left,right
@@ -124,7 +124,7 @@ priority = 2
 direction = output
 
 [Mapping hdmi-surround-extra1]
-description = Digital Surround 5.1 (HDMI)
+description = Digital Surround 5.1 (HDMI 2)
 device-strings = hdmi:%f,1
 paths-output = hdmi-output-1
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
@@ -132,7 +132,7 @@ priority = 1
 direction = output
 
 [Mapping hdmi-stereo-extra2]
-description = Digital Stereo (HDMI)
+description = Digital Stereo (HDMI 3)
 device-strings = hdmi:%f,2
 paths-output = hdmi-output-2
 channel-map = left,right
@@ -140,7 +140,7 @@ priority = 2
 direction = output
 
 [Mapping hdmi-surround-extra2]
-description = Digital Surround 5.1 (HDMI)
+description = Digital Surround 5.1 (HDMI 3)
 device-strings = hdmi:%f,2
 paths-output = hdmi-output-2
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
@@ -148,7 +148,7 @@ priority = 1
 direction = output
 
 [Mapping hdmi-stereo-extra3]
-description = Digital Stereo (HDMI)
+description = Digital Stereo (HDMI 4)
 device-strings = hdmi:%f,3
 paths-output = hdmi-output-3
 channel-map = left,right
@@ -156,7 +156,7 @@ priority = 2
 direction = output
 
 [Mapping hdmi-surround-extra3]
-description = Digital Surround 5.1 (HDMI)
+description = Digital Surround 5.1 (HDMI 4)
 device-strings = hdmi:%f,3
 paths-output = hdmi-output-3
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
++++++ 0007-sink-source-Assign-to-s-muted-from-only-one-place.patch ++++++
>From e4a7625ba884c5cce20468d75937857343751c35 Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaski...@linux.intel.com>
Date: Tue, 15 Apr 2014 13:56:10 +0300
Subject: [PATCH] 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.
---
 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(-)

--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -1395,18 +1395,17 @@ static void sink_write_volume_cb(pa_sink
     }
 }
 
-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) {
@@ -2390,8 +2389,12 @@ pa_sink *pa_alsa_sink_new(pa_module *m,
         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)
--- 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_so
     }
 }
 
-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
         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)
--- 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) {
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -515,7 +515,7 @@ void pa_sink_set_write_volume_callback(p
         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;
@@ -2252,21 +2252,15 @@ bool pa_sink_get_mute(pa_sink *s, bool f
     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);
         }
     }
 
@@ -2775,7 +2769,7 @@ int pa_sink_process_msg(pa_msgobject *o,
         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;
 
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -58,6 +58,8 @@ static inline bool PA_SINK_IS_LINKED(pa_
 /* 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;
 
@@ -189,14 +191,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
@@ -377,7 +389,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);
 
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -467,7 +467,7 @@ void pa_source_set_write_volume_callback
         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;
@@ -1847,21 +1847,15 @@ bool pa_source_get_mute(pa_source *s, bo
     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);
         }
     }
 
@@ -2146,7 +2140,7 @@ int pa_source_process_msg(pa_msgobject *
         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;
 
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -58,6 +58,8 @@ static inline bool PA_SOURCE_IS_LINKED(p
 /* 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;
 
@@ -156,14 +158,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_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_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
@@ -314,7 +326,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);
 
++++++ 0008-alsa-mixer-Add-surround-2.1-profile.patch ++++++
>From 3f140f9022ef0b59b3684edd25e2202a65989669 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Fri, 23 May 2014 14:21:27 +0200
Subject: [PATCH] alsa-mixer: Add surround 2.1 profile

Surround 2.1 is one of the more common surround profiles these days,
so it's about time we support it.

The "surround21" was added to alsa-lib a few months ago, and there
hasn't yet been an alsa-lib release since, but I doubt it will change.

Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/mixer/profile-sets/default.conf                   |    7 
+++++++
 src/modules/alsa/mixer/profile-sets/extra-hdmi.conf                |    7 
+++++++
 src/modules/alsa/mixer/profile-sets/force-speaker-and-int-mic.conf |    7 
+++++++
 src/modules/alsa/mixer/profile-sets/force-speaker.conf             |    7 
+++++++
 4 files changed, 28 insertions(+)

--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -112,6 +112,13 @@ paths-output = analog-output analog-outp
 paths-input = analog-input-front-mic analog-input-rear-mic 
analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic 
analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner 
analog-input-fm analog-input-mic-line analog-input-headphone-mic 
analog-input-headset-mic
 priority = 10
 
+[Mapping analog-surround-21]
+device-strings = surround21:%f
+channel-map = front-left,front-right,lfe
+paths-output = analog-output analog-output-speaker 
analog-output-desktop-speaker
+priority = 8
+direction = output
+
 [Mapping analog-surround-40]
 device-strings = surround40:%f
 channel-map = front-left,front-right,rear-left,rear-right
--- a/src/modules/alsa/mixer/profile-sets/extra-hdmi.conf
+++ b/src/modules/alsa/mixer/profile-sets/extra-hdmi.conf
@@ -38,6 +38,13 @@ paths-output = analog-output analog-outp
 paths-input = analog-input-front-mic analog-input-rear-mic 
analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic 
analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner 
analog-input-fm analog-input-mic-line analog-input-headphone-mic 
analog-input-headset-mic
 priority = 10
 
+[Mapping analog-surround-21]
+device-strings = surround21:%f
+channel-map = front-left,front-right,lfe
+paths-output = analog-output analog-output-speaker 
analog-output-desktop-speaker
+priority = 8
+direction = output
+
 [Mapping analog-surround-40]
 device-strings = surround40:%f
 channel-map = front-left,front-right,rear-left,rear-right
--- a/src/modules/alsa/mixer/profile-sets/force-speaker-and-int-mic.conf
+++ b/src/modules/alsa/mixer/profile-sets/force-speaker-and-int-mic.conf
@@ -35,6 +35,13 @@ paths-output = analog-output analog-outp
 paths-input = analog-input-front-mic analog-input-rear-mic 
analog-input-internal-mic-always analog-input-dock-mic analog-input 
analog-input-mic analog-input-linein analog-input-aux analog-input-video 
analog-input-tvtuner analog-input-fm analog-input-mic-line
 priority = 10
 
+[Mapping analog-surround-21]
+device-strings = surround21:%f
+channel-map = front-left,front-right,lfe
+paths-output = analog-output analog-output-speaker-always 
analog-output-desktop-speaker
+priority = 8
+direction = output
+
 [Mapping analog-surround-40]
 device-strings = surround40:%f
 channel-map = front-left,front-right,rear-left,rear-right
--- a/src/modules/alsa/mixer/profile-sets/force-speaker.conf
+++ b/src/modules/alsa/mixer/profile-sets/force-speaker.conf
@@ -34,6 +34,13 @@ paths-output = analog-output analog-outp
 paths-input = analog-input-front-mic analog-input-rear-mic 
analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic 
analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner 
analog-input-fm analog-input-mic-line
 priority = 10
 
+[Mapping analog-surround-21]
+device-strings = surround21:%f
+channel-map = front-left,front-right,lfe
+paths-output = analog-output analog-output-speaker-always 
analog-output-desktop-speaker
+priority = 8
+direction = output
+
 [Mapping analog-surround-40]
 device-strings = surround40:%f
 channel-map = front-left,front-right,rear-left,rear-right
++++++ 0009-alsa-Add-extra-HDMI-mappings.patch ++++++
++++ 632 lines (skipped)

++++++ 0010-alsa-Add-exact-channels-mapping-configurability.patch ++++++
>From be8311417caedc3c5a539cc06a7549bfdbd167e3 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Fri, 25 Jul 2014 14:57:55 +0200
Subject: [PATCH] alsa: Add "exact-channels" mapping configurability

Allow a mapping to relax the exact channel restriction:

exact-channels = yes | no # If no, and the exact number of channels is not 
supported,
                          # allow device to be opened with another channel count

Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/alsa-mixer.c                    |   43 ++++++++++++++++++++---
 src/modules/alsa/alsa-mixer.h                    |    1 
 src/modules/alsa/mixer/profile-sets/default.conf |    2 +
 3 files changed, 42 insertions(+), 4 deletions(-)

--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -3368,6 +3368,7 @@ pa_alsa_mapping *pa_alsa_mapping_get(pa_
 
     m = pa_xnew0(pa_alsa_mapping, 1);
     m->profile_set = ps;
+    m->exact_channels = true;
     m->name = pa_xstrdup(name);
     pa_sample_spec_init(&m->sample_spec);
     pa_channel_map_init(&m->channel_map);
@@ -3485,6 +3486,30 @@ static int mapping_parse_paths(pa_config
     return 0;
 }
 
+static int mapping_parse_exact_channels(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
+    pa_alsa_mapping *m;
+    int b;
+
+    pa_assert(state);
+
+    ps = state->userdata;
+
+    if (!(m = pa_alsa_mapping_get(ps, state->section))) {
+        pa_log("[%s:%u] %s invalid in section %s", state->filename, 
state->lineno, state->lvalue, state->section);
+        return -1;
+    }
+
+    if ((b = pa_parse_boolean(state->rvalue)) < 0) {
+        pa_log("[%s:%u] %s has invalid value '%s'", state->filename, 
state->lineno, state->lvalue, state->section);
+        return -1;
+    }
+
+    m->exact_channels = b;
+
+    return 0;
+}
+
 static int mapping_parse_element(pa_config_parser_state *state) {
     pa_alsa_profile_set *ps;
     pa_alsa_mapping *m;
@@ -4156,6 +4181,7 @@ pa_alsa_profile_set* pa_alsa_profile_set
         { "element-input",          mapping_parse_element,        NULL, NULL },
         { "element-output",         mapping_parse_element,        NULL, NULL },
         { "direction",              mapping_parse_direction,      NULL, NULL },
+        { "exact-channels",         mapping_parse_exact_channels, NULL, NULL },
 
         /* Shared by [Mapping ...] and [Profile ...] */
         { "description",            mapping_parse_description,    NULL, NULL },
@@ -4264,10 +4290,12 @@ static void profile_finalize_probing(pa_
 static snd_pcm_t* mapping_open_pcm(pa_alsa_mapping *m,
                                    const pa_sample_spec *ss,
                                    const char *dev_id,
+                                   bool exact_channels,
                                    int mode,
                                    unsigned default_n_fragments,
                                    unsigned default_fragment_size_msec) {
 
+    snd_pcm_t* handle;
     pa_sample_spec try_ss = *ss;
     pa_channel_map try_map = m->channel_map;
     snd_pcm_uframes_t try_period_size, try_buffer_size;
@@ -4279,10 +4307,17 @@ static snd_pcm_t* mapping_open_pcm(pa_al
         pa_frame_size(&try_ss);
     try_buffer_size = default_n_fragments * try_period_size;
 
-    return pa_alsa_open_by_template(
+    handle = pa_alsa_open_by_template(
                               m->device_strings, dev_id, NULL, &try_ss,
                               &try_map, mode, &try_period_size,
-                              &try_buffer_size, 0, NULL, NULL, true);
+                              &try_buffer_size, 0, NULL, NULL, exact_channels);
+    if (handle && !exact_channels && m->channel_map.channels != 
try_map.channels) {
+        char buf[PA_CHANNEL_MAP_SNPRINT_MAX];
+        pa_log_debug("Channel map for mapping '%s' permanently changed to 
'%s'", m->name,
+                     pa_channel_map_snprint(buf, sizeof(buf), &try_map));
+        m->channel_map = try_map;
+    }
+    return handle;
 }
 
 static void paths_drop_unused(pa_hashmap* h, pa_hashmap *keep) {
@@ -4367,7 +4402,7 @@ void pa_alsa_profile_set_probe(
                         continue;
 
                     pa_log_debug("Checking for playback on %s (%s)", 
m->description, m->name);
-                    if (!(m->output_pcm = mapping_open_pcm(m, ss, dev_id,
+                    if (!(m->output_pcm = mapping_open_pcm(m, ss, dev_id, 
m->exact_channels,
                                                            
SND_PCM_STREAM_PLAYBACK,
                                                            default_n_fragments,
                                                            
default_fragment_size_msec))) {
@@ -4388,7 +4423,7 @@ void pa_alsa_profile_set_probe(
                         continue;
 
                     pa_log_debug("Checking for recording on %s (%s)", 
m->description, m->name);
-                    if (!(m->input_pcm = mapping_open_pcm(m, ss, dev_id,
+                    if (!(m->input_pcm = mapping_open_pcm(m, ss, dev_id, 
m->exact_channels,
                                                           
SND_PCM_STREAM_CAPTURE,
                                                           default_n_fragments,
                                                           
default_fragment_size_msec))) {
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -264,6 +264,7 @@ struct pa_alsa_mapping {
     pa_alsa_path_set *output_path_set;
 
     unsigned supported;
+    bool exact_channels:1;
 
     /* Temporarily used during probing */
     snd_pcm_t *input_pcm;
--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -55,6 +55,8 @@
 ; priority = ...
 ; direction = any | input | output          # Only useful for?
 ;
+; exact-channels = yes | no                 # If no, and the exact number of 
channels is not supported,
+;                                           # allow device to be opened with 
another channel count
 ; [Profile id]
 ; input-mappings = ...                      # Lists mappings for sources on 
this profile, those mapping must be
 ;                                           # defined in this file too
++++++ 0011-alsa-Allow-fallback-configuration-for-mappings-and-p.patch ++++++
>From c15107eaf6045711d799a71204a8f94a1c424182 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Fri, 25 Jul 2014 15:05:45 +0200
Subject: [PATCH] alsa: Allow "fallback" configuration for mappings and
 profiles

A fallback mapping or profile will only be considered for probing
if all non-fallback profiles fail.

If auto-profiles are used, a profile made up of one non-fallback
mapping and one fallback mapping will be considered a fallback profile.

Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/alsa-mixer.c                    |   77 +++++++++++++++++++++--
 src/modules/alsa/alsa-mixer.h                    |    3 
 src/modules/alsa/mixer/profile-sets/default.conf |    2 
 3 files changed, 78 insertions(+), 4 deletions(-)

--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -3611,6 +3611,34 @@ static int mapping_parse_priority(pa_con
     return 0;
 }
 
+static int mapping_parse_fallback(pa_config_parser_state *state) {
+    pa_alsa_profile_set *ps;
+    pa_alsa_profile *p;
+    pa_alsa_mapping *m;
+    int k;
+
+    pa_assert(state);
+
+    ps = state->userdata;
+
+    if ((k = pa_parse_boolean(state->rvalue)) < 0) {
+        pa_log("[%s:%u] Fallback invalid of '%s'", state->filename, 
state->lineno, state->section);
+        return -1;
+    }
+
+    if ((m = pa_alsa_mapping_get(ps, state->section)))
+        m->fallback = k;
+    else if ((p = profile_get(ps, state->section)))
+        p->fallback_input = p->fallback_output = k;
+    else {
+        pa_log("[%s:%u] Section name %s invalid.", state->filename, 
state->lineno, state->section);
+        return -1;
+    }
+
+    return 0;
+}
+
+
 static int profile_parse_mappings(pa_config_parser_state *state) {
     pa_alsa_profile_set *ps;
     pa_alsa_profile *p;
@@ -3939,12 +3967,14 @@ static void profile_set_add_auto_pair(
         p->output_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, 
pa_idxset_trivial_compare_func);
         pa_idxset_put(p->output_mappings, m, NULL);
         p->priority += m->priority * 100;
+        p->fallback_output = m->fallback;
     }
 
     if (n) {
         p->input_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, 
pa_idxset_trivial_compare_func);
         pa_idxset_put(p->input_mappings, n, NULL);
         p->priority += n->priority;
+        p->fallback_input = n->fallback;
     }
 
     pa_hashmap_put(ps->profiles, p->name, p);
@@ -4186,6 +4216,7 @@ pa_alsa_profile_set* pa_alsa_profile_set
         /* Shared by [Mapping ...] and [Profile ...] */
         { "description",            mapping_parse_description,    NULL, NULL },
         { "priority",               mapping_parse_priority,       NULL, NULL },
+        { "fallback",               mapping_parse_fallback,       NULL, NULL },
 
         /* [Profile ...] */
         { "input-mappings",         profile_parse_mappings,       NULL, NULL },
@@ -4339,6 +4370,24 @@ static void paths_drop_unused(pa_hashmap
     }
 }
 
+static int add_profiles_to_probe(
+        pa_alsa_profile **list,
+        pa_hashmap *profiles,
+        bool fallback_output,
+        bool fallback_input) {
+
+    int i = 0;
+    void *state;
+    pa_alsa_profile *p;
+    PA_HASHMAP_FOREACH(p, profiles, state)
+        if (p->fallback_input == fallback_input && p->fallback_output == 
fallback_output) {
+            *list = p;
+            list++;
+            i++;
+        }
+    return i;
+}
+
 void pa_alsa_profile_set_probe(
         pa_alsa_profile_set *ps,
         const char *dev_id,
@@ -4346,8 +4395,10 @@ void pa_alsa_profile_set_probe(
         unsigned default_n_fragments,
         unsigned default_fragment_size_msec) {
 
-    void *state;
+    bool found_output = false, found_input = false;
+
     pa_alsa_profile *p, *last = NULL;
+    pa_alsa_profile **pp, **probe_order;
     pa_alsa_mapping *m;
     pa_hashmap *broken_inputs, *broken_outputs, *used_paths;
 
@@ -4361,9 +4412,22 @@ void pa_alsa_profile_set_probe(
     broken_inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, 
pa_idxset_trivial_compare_func);
     broken_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, 
pa_idxset_trivial_compare_func);
     used_paths = pa_hashmap_new(pa_idxset_trivial_hash_func, 
pa_idxset_trivial_compare_func);
+    pp = probe_order = pa_xnew0(pa_alsa_profile *, 
pa_hashmap_size(ps->profiles) + 1);
+
+    pp += add_profiles_to_probe(pp, ps->profiles, false, false);
+    pp += add_profiles_to_probe(pp, ps->profiles, false, true);
+    pp += add_profiles_to_probe(pp, ps->profiles, true, false);
+    pp += add_profiles_to_probe(pp, ps->profiles, true, true);
 
-    PA_HASHMAP_FOREACH(p, ps->profiles, state) {
+    for (pp = probe_order; *pp; pp++) {
         uint32_t idx;
+        p = *pp;
+
+        /* Skip if fallback and already found something */
+        if (found_input && p->fallback_input)
+            continue;
+        if (found_output && p->fallback_output)
+            continue;
 
         /* Skip if this is already marked that it is supported (i.e. from the 
config file) */
         if (!p->supported) {
@@ -4447,13 +4511,17 @@ void pa_alsa_profile_set_probe(
 
         if (p->output_mappings)
             PA_IDXSET_FOREACH(m, p->output_mappings, idx)
-                if (m->output_pcm)
+                if (m->output_pcm) {
+                    found_output |= !p->fallback_output;
                     mapping_paths_probe(m, p, PA_ALSA_DIRECTION_OUTPUT, 
used_paths);
+                }
 
         if (p->input_mappings)
             PA_IDXSET_FOREACH(m, p->input_mappings, idx)
-                if (m->input_pcm)
+                if (m->input_pcm) {
+                    found_input |= !p->fallback_input;
                     mapping_paths_probe(m, p, PA_ALSA_DIRECTION_INPUT, 
used_paths);
+                }
     }
 
     /* Clean up */
@@ -4466,6 +4534,7 @@ void pa_alsa_profile_set_probe(
     pa_hashmap_free(broken_inputs);
     pa_hashmap_free(broken_outputs);
     pa_hashmap_free(used_paths);
+    pa_xfree(probe_order);
 
     ps->probed = true;
 }
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -265,6 +265,7 @@ struct pa_alsa_mapping {
 
     unsigned supported;
     bool exact_channels:1;
+    bool fallback:1;
 
     /* Temporarily used during probing */
     snd_pcm_t *input_pcm;
@@ -285,6 +286,8 @@ struct pa_alsa_profile {
     unsigned priority;
 
     bool supported:1;
+    bool fallback_input:1;
+    bool fallback_output:1;
 
     char **input_mapping_names;
     char **output_mapping_names;
--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -57,6 +57,7 @@
 ;
 ; exact-channels = yes | no                 # If no, and the exact number of 
channels is not supported,
 ;                                           # allow device to be opened with 
another channel count
+; fallback = no | yes                       # This mapping will only be 
considered if all non-fallback mappings fail
 ; [Profile id]
 ; input-mappings = ...                      # Lists mappings for sources on 
this profile, those mapping must be
 ;                                           # defined in this file too
@@ -68,6 +69,7 @@
 ;                                           # will be assumed as working 
without probing. Makes initialization
 ;                                           # a bit faster but only works if 
the card is really known well.
 ;
+; fallback = no | yes                       # This profile will only be 
considered if all non-fallback profiles fail
 ; [DecibelFix element]                      # Decibel fixes can be used to 
work around missing or incorrect dB
 ;                                           # information from alsa. A decibel 
fix is a table that maps volume steps
 ;                                           # to decibel values for one volume 
element. The "element" part in the
++++++ 0012-alsa-Add-a-multichannel-fallback-mapping.patch ++++++
>From 48edd0a00f455df075efcf1986103e5f507c816f Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Fri, 25 Jul 2014 15:16:41 +0200
Subject: [PATCH] alsa: Add a multichannel fallback mapping

In case all other profiles fail, try this fallback mapping as well.
It allows the device to specify the channel count, so it can be used
for devices that only supports being opened in multichannel mode.

Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/alsa-mixer.c                    |    1 +
 src/modules/alsa/mixer/profile-sets/default.conf |   11 +++++++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -3859,6 +3859,7 @@ static int mapping_verify(pa_alsa_mappin
     static const struct description_map well_known_descriptions[] = {
         { "analog-mono",            N_("Analog Mono") },
         { "analog-stereo",          N_("Analog Stereo") },
+        { "multichannel",           N_("Multichannel") },
         { "analog-surround-21",     N_("Analog Surround 2.1") },
         { "analog-surround-30",     N_("Analog Surround 3.0") },
         { "analog-surround-31",     N_("Analog Surround 3.1") },
--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -107,7 +107,7 @@ device-strings = hw:%f
 channel-map = mono
 paths-output = analog-output analog-output-lineout analog-output-speaker 
analog-output-desktop-speaker analog-output-headphones 
analog-output-headphones-2 analog-output-mono
 paths-input = analog-input-front-mic analog-input-rear-mic 
analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic 
analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner 
analog-input-fm analog-input-mic-line analog-input-headset-mic
-priority = 1
+priority = 2
 
 [Mapping analog-stereo]
 device-strings = front:%f hw:%f
@@ -165,7 +165,7 @@ direction = output
 # device name standardized in alsa.
 device-strings = hw:%f
 channel-map = aux0,aux1,aux2,aux3
-priority = 1
+priority = 2
 direction = input
 
 [Mapping iec958-stereo]
@@ -452,6 +452,13 @@ channel-map = front-left,front-right,rea
 priority = 1
 direction = output
 
+[Mapping multichannel]
+device-strings = hw:%f
+channel-map = left,right,rear-left,rear-right
+exact-channels = false
+fallback = yes
+priority = 1
+
 ; An example for defining multiple-sink profiles
 #[Profile output:analog-stereo+output:iec958-stereo+input:analog-stereo]
 #description = Foobar
++++++ 0013-alsa-mixer-Fix-path-subset-detection.patch ++++++
>From facfd3a6644711d32ecfd755d30a351b8ee61620 Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaski...@linux.intel.com>
Date: Sun, 17 Aug 2014 14:52:29 +0300
Subject: [PATCH] alsa-mixer: Fix path subset detection

The old logic assumed that if path A was a subset of path B, the
element list in B would have all elements of A in the beginning of
B's list, in the same order as A. This assumption was invalid, causing
some subset cases to not get detected. We need to search through the
full element list of B every time before we can conclude that B
doesn't have the element that we're inspecting.
---
 src/modules/alsa/alsa-mixer.c |   26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -3218,21 +3218,21 @@ static void path_set_condense(pa_alsa_pa
             }
 
             /* Compare the elements of each set... */
-            ea = p->elements;
-            eb = p2->elements;
+            PA_LLIST_FOREACH(ea, p->elements) {
+                bool found_matching_element = false;
 
-            while (is_subset) {
-                if (!ea && !eb)
+                if (!is_subset)
                     break;
-                else if ((ea && !eb) || (!ea && eb))
-                    is_subset = false;
-                else if (pa_streq(ea->alsa_name, eb->alsa_name)) {
-                    if (element_is_subset(ea, eb, m)) {
-                        ea = ea->next;
-                        eb = eb->next;
-                    } else
-                        is_subset = false;
-                } else
+
+                PA_LLIST_FOREACH(eb, p2->elements) {
+                    if (pa_streq(ea->alsa_name, eb->alsa_name)) {
+                        found_matching_element = true;
+                        is_subset = element_is_subset(ea, eb, m);
+                        break;
+                    }
+                }
+
+                if (!found_matching_element)
                     is_subset = false;
             }
 
++++++ 0014-alsa-Remove-four-channel-input-profile.patch ++++++
>From 2575b102b9f8f0ba6d604ff8014136a2e3241ca4 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Fri, 1 Aug 2014 18:09:42 +0200
Subject: [PATCH] alsa: Remove four channel input profile

With the new multichannel profile, we can remove this one and
handle the four channel input as a generic multichannel fallback.

Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/alsa-mixer.c                    |    1 -
 src/modules/alsa/mixer/profile-sets/default.conf |    9 ---------
 2 files changed, 10 deletions(-)

--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -3871,7 +3871,6 @@ static int mapping_verify(pa_alsa_mappin
         { "analog-surround-61",     N_("Analog Surround 6.1") },
         { "analog-surround-70",     N_("Analog Surround 7.0") },
         { "analog-surround-71",     N_("Analog Surround 7.1") },
-        { "analog-4-channel-input", N_("Analog 4-channel Input") },
         { "iec958-stereo",          N_("Digital Stereo (IEC958)") },
         { "iec958-passthrough",     N_("Digital Passthrough  (IEC958)") },
         { "iec958-ac3-surround-40", N_("Digital Surround 4.0 (IEC958/AC3)") },
--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -159,15 +159,6 @@ paths-output = analog-output analog-outp
 priority = 7
 direction = output
 
-[Mapping analog-4-channel-input]
-# Alsa doesn't currently provide any better device name than "hw" for 4-channel
-# input. If this causes trouble at some point, then we will need to get a new
-# device name standardized in alsa.
-device-strings = hw:%f
-channel-map = aux0,aux1,aux2,aux3
-priority = 2
-direction = input
-
 [Mapping iec958-stereo]
 device-strings = iec958:%f
 channel-map = left,right
++++++ 0015-alsa-mixer-Mark-Line-HP-Swap-as-required-any.patch ++++++
>From 610704d225675d1d112cf1973bde9edb420ec37e Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaski...@linux.intel.com>
Date: Sun, 7 Sep 2014 15:20:18 +0300
Subject: [PATCH] alsa-mixer: Mark "Line HP Swap" as required-any

In the (theoretical) case that no other elements exists but
"Line HP Swap", the presence of that element signals that there are
headphone and line-out outputs, otherwise there would be nothing to
swap.
---
 src/modules/alsa/mixer/paths/analog-output-headphones.conf |    1 +
 src/modules/alsa/mixer/paths/analog-output-lineout.conf    |    1 +
 2 files changed, 2 insertions(+)

--- a/src/modules/alsa/mixer/paths/analog-output-headphones.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-headphones.conf
@@ -77,6 +77,7 @@ override-map.2 = all-left,all-right
 
 [Element Line HP Swap]
 switch = on
+required-any = any
 
 ; This profile path is intended to control the first headphones, not
 ; the second headphones. But it should not hurt if we leave the second
--- a/src/modules/alsa/mixer/paths/analog-output-lineout.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-lineout.conf
@@ -82,6 +82,7 @@ volume = off
 
 [Element Line HP Swap]
 switch = off
+required-any = any
 
 ; This profile path is intended to control the default output, not the
 ; headphones. But it should not hurt if we leave the headphone jack
++++++ 0017-alsa-mixer-recognize-Dock-headphone-jack.patch ++++++
>From 594da41d07edcebc5fd319388852a66cc3f12ace Mon Sep 17 00:00:00 2001
From: Sjoerd Simons <sjo...@luon.net>
Date: Sun, 31 Aug 2014 20:11:21 +0200
Subject: [PATCH] alsa-mixer: recognize Dock headphone jack

Recognize the Dock headphone jack in the same way the normal & front
headphone jacks are detected.

Reviewed-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/mixer/paths/analog-output-headphones.conf |    8 ++++++++
 src/modules/alsa/mixer/paths/analog-output-speaker.conf    |    4 ++++
 2 files changed, 12 insertions(+)

--- a/src/modules/alsa/mixer/paths/analog-output-headphones.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-headphones.conf
@@ -25,6 +25,14 @@ description-key = analog-output-headphon
 [Properties]
 device.icon_name = audio-headphones
 
+[Jack Dock Headphone]
+required-any = any
+
+[Jack Dock Headphone Phantom]
+required-any = any
+state.plugged = unknown
+state.unplugged = unknown
+
 [Jack Front Headphone]
 required-any = any
 
--- a/src/modules/alsa/mixer/paths/analog-output-speaker.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-speaker.conf
@@ -29,6 +29,10 @@ device.icon_name = audio-speakers
 state.plugged = no
 state.unplugged = unknown
 
+[Jack Dock Headphone]
+state.plugged = no
+state.unplugged = unknown
+
 [Jack Front Headphone]
 state.plugged = no
 state.unplugged = unknown
++++++ 0018-alsa-util-Add-functions-for-accessing-mixer-elements.patch ++++++
>From 1fd8848e64cfb352d0ab12ee27c8c667d81a8f6d Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Mon, 1 Sep 2014 15:38:25 +0200
Subject: [PATCH] alsa-util: Add functions for accessing mixer elements through
 mixer class

Instead of using the hctl interface, we can find controls belonging
to other iface types than "mixer". We do this by introducing a new
mixer class "SND_MIXER_ELEM_PULSEAUDIO" and create snd_mixer_elem's
for all PCM and CARD iface types (as Jacks are of the CARD type and
ELD controls are of the PCM type).

Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/alsa-util.c |   77 +++++++++++++++++++++++++++++++++++++++++++
 src/modules/alsa/alsa-util.h |    2 +
 2 files changed, 79 insertions(+)

--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -1457,6 +1457,25 @@ bool pa_alsa_may_tsched(bool want) {
     return true;
 }
 
+#define SND_MIXER_ELEM_PULSEAUDIO (SND_MIXER_ELEM_LAST + 10)
+
+snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, const char *name, 
unsigned int device) {
+    snd_mixer_elem_t *elem;
+
+    for (elem = snd_mixer_first_elem(mixer); elem; elem = 
snd_mixer_elem_next(elem)) {
+        snd_hctl_elem_t *helem;
+        if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_PULSEAUDIO)
+            continue;
+        helem = snd_mixer_elem_get_private(elem);
+        if (!pa_streq(snd_hctl_elem_get_name(helem), name))
+            continue;
+        if (snd_hctl_elem_get_device(helem) != device)
+            continue;
+        return elem;
+    }
+    return NULL;
+}
+
 snd_hctl_elem_t* pa_alsa_find_jack(snd_hctl_t *hctl, const char* jack_name) {
     snd_ctl_elem_id_t *id;
 
@@ -1481,8 +1500,53 @@ snd_hctl_elem_t* pa_alsa_find_eld_ctl(sn
     return snd_hctl_find_elem(hctl, id);
 }
 
+static int mixer_class_compare(const snd_mixer_elem_t *c1, const 
snd_mixer_elem_t *c2)
+{
+    /* Dummy compare function */
+    return c1 == c2 ? 0 : (c1 > c2 ? 1 : -1);
+}
+
+static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask,
+                       snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
+{
+    int err;
+    const char *name = snd_hctl_elem_get_name(helem);
+    if (mask & SND_CTL_EVENT_MASK_ADD) {
+        snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
+        if (iface == SND_CTL_ELEM_IFACE_CARD || iface == 
SND_CTL_ELEM_IFACE_PCM) {
+            snd_mixer_elem_t *new_melem;
+
+            /* Put the hctl pointer as our private data - it will be useful 
for callbacks */
+            if ((err = snd_mixer_elem_new(&new_melem, 
SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) {
+                pa_log_warn("snd_mixer_elem_new failed: %s", 
pa_alsa_strerror(err));
+                return 0;
+            }
+
+            if ((err = snd_mixer_elem_attach(new_melem, helem)) < 0) {
+                pa_log_warn("snd_mixer_elem_attach failed: %s", 
pa_alsa_strerror(err));
+               snd_mixer_elem_free(melem);
+                return 0;
+            }
+
+            if ((err = snd_mixer_elem_add(new_melem, class)) < 0) {
+                pa_log_warn("snd_mixer_elem_add failed: %s", 
pa_alsa_strerror(err));
+                return 0;
+            }
+        }
+    }
+    else if (mask & SND_CTL_EVENT_MASK_VALUE) {
+        snd_mixer_elem_value(melem); /* Calls the element callback */
+        return 0;
+    }
+    else
+        pa_log_info("Got an unknown mixer class event for %s: mask 0x%x\n", 
name, mask);
+
+    return 0;
+}
+
 static int prepare_mixer(snd_mixer_t *mixer, const char *dev, snd_hctl_t 
**hctl) {
     int err;
+    snd_mixer_class_t *class;
 
     pa_assert(mixer);
     pa_assert(dev);
@@ -1499,6 +1563,19 @@ static int prepare_mixer(snd_mixer_t *mi
         return -1;
     }
 
+    if (snd_mixer_class_malloc(&class)) {
+        pa_log_info("Failed to allocate mixer class for %s", dev);
+        return -1;
+    }
+    snd_mixer_class_set_event(class, mixer_class_event);
+    snd_mixer_class_set_compare(class, mixer_class_compare);
+    if ((err = snd_mixer_class_register(class, mixer)) < 0) {
+        pa_log_info("Unable register mixer class for %s: %s", dev, 
pa_alsa_strerror(err));
+        snd_mixer_class_free(class);
+        return -1;
+    }
+    /* From here on, the mixer class is deallocated by alsa on 
snd_mixer_close/free. */
+
     if ((err = snd_mixer_selem_register(mixer, NULL, NULL)) < 0) {
         pa_log_warn("Unable to register mixer: %s", pa_alsa_strerror(err));
         return -1;
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -145,6 +145,8 @@ bool pa_alsa_may_tsched(bool want);
 snd_hctl_elem_t* pa_alsa_find_jack(snd_hctl_t *hctl, const char* jack_name);
 snd_hctl_elem_t* pa_alsa_find_eld_ctl(snd_hctl_t *hctl, int device);
 
+snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, const char *name, 
unsigned int device);
+
 snd_mixer_t *pa_alsa_open_mixer(int alsa_card_index, char **ctl_device, 
snd_hctl_t **hctl);
 
 typedef struct pa_hdmi_eld pa_hdmi_eld;
++++++ 0019-alsa-mixer-card-Move-to-use-the-new-mixer-interface.patch ++++++
>From f2120fc2b69579d51a2e1874649739a799815be9 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Mon, 1 Sep 2014 15:41:39 +0200
Subject: [PATCH] alsa-mixer/card: Move to use the new mixer interface

Use the new mixer API to get callbacks, instead of using the hctl
API. Using the hctl API caused a memory leak, because alsa-lib itself
used the hctl callbacks, which we were previously overriding.

Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/alsa-mixer.c       |    7 ++----
 src/modules/alsa/alsa-mixer.h       |    2 -
 src/modules/alsa/module-alsa-card.c |   41 ++++++++++++++++++------------------
 3 files changed, 25 insertions(+), 25 deletions(-)

--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -1682,12 +1682,11 @@ static int element_probe(pa_alsa_element
     return 0;
 }
 
-static int jack_probe(pa_alsa_jack *j, snd_hctl_t *h) {
-    pa_assert(h);
+static int jack_probe(pa_alsa_jack *j, snd_mixer_t *m) {
     pa_assert(j);
     pa_assert(j->path);
 
-    j->has_control = pa_alsa_find_jack(h, j->alsa_name) != NULL;
+    j->has_control = pa_alsa_mixer_find(m, j->alsa_name, 0) != NULL;
 
     if (j->has_control) {
         if (j->required_absent != PA_ALSA_REQUIRED_IGNORE)
@@ -2635,7 +2634,7 @@ int pa_alsa_path_probe(pa_alsa_path *p,
     pa_log_debug("Probing path '%s'", p->name);
 
     PA_LLIST_FOREACH(j, p->jacks) {
-        if (jack_probe(j, hctl) < 0) {
+        if (jack_probe(j, m) < 0) {
             p->supported = false;
             pa_log_debug("Probe of jack '%s' failed.", j->alsa_name);
             return -1;
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -164,7 +164,7 @@ struct pa_alsa_jack {
     char *alsa_name; /* E g "Headphone Jack" */
     bool has_control; /* is the jack itself present? */
     bool plugged_in; /* is this jack currently plugged in? */
-    snd_hctl_elem_t *hctl_elem; /* Jack detection handle */
+    snd_mixer_elem_t *melem; /* Jack detection handle */
     pa_available_t state_unplugged, state_plugged;
 
     pa_alsa_required_t required;
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -350,8 +350,9 @@ static void report_port_state(pa_device_
     pa_device_port_set_available(p, pa);
 }
 
-static int report_jack_state(snd_hctl_elem_t *elem, unsigned int mask) {
-    struct userdata *u = snd_hctl_elem_get_callback_private(elem);
+static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
+    struct userdata *u = snd_mixer_elem_get_callback_private(melem);
+    snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem);
     snd_ctl_elem_value_t *elem_value;
     bool plugged_in;
     void *state;
@@ -374,7 +375,7 @@ static int report_jack_state(snd_hctl_el
     pa_log_debug("Jack '%s' is now %s", 
pa_strnull(snd_hctl_elem_get_name(elem)), plugged_in ? "plugged in" : 
"unplugged");
 
     PA_HASHMAP_FOREACH(jack, u->jacks, state)
-        if (jack->hctl_elem == elem) {
+        if (jack->melem == melem) {
             jack->plugged_in = plugged_in;
             if (u->use_ucm) {
                 pa_assert(u->card->ports);
@@ -403,8 +404,9 @@ static pa_device_port* find_port_with_el
     return NULL;
 }
 
-static int hdmi_eld_changed(snd_hctl_elem_t *elem, unsigned int mask) {
-    struct userdata *u = snd_hctl_elem_get_callback_private(elem);
+static int hdmi_eld_changed(snd_mixer_elem_t *melem, unsigned int mask) {
+    struct userdata *u = snd_mixer_elem_get_callback_private(melem);
+    snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem);
     int device = snd_hctl_elem_get_device(elem);
     const char *old_monitor_name;
     pa_device_port *p;
@@ -447,7 +449,7 @@ static void init_eld_ctls(struct userdat
 
     PA_HASHMAP_FOREACH(port, u->card->ports, state) {
         pa_alsa_port_data *data = PA_DEVICE_PORT_DATA(port);
-        snd_hctl_elem_t* hctl_elem;
+        snd_mixer_elem_t* melem;
         int device;
 
         pa_assert(data->path);
@@ -455,15 +457,14 @@ static void init_eld_ctls(struct userdat
         if (device < 0)
             continue;
 
-        hctl_elem = pa_alsa_find_eld_ctl(u->hctl_handle, device);
-        if (!hctl_elem) {
-            pa_log_debug("No ELD device found for port %s.", port->name);
-            continue;
+        melem = pa_alsa_mixer_find(u->mixer_handle, "ELD", device);
+        if (melem) {
+            snd_mixer_elem_set_callback(melem, hdmi_eld_changed);
+            snd_mixer_elem_set_callback_private(melem, u);
+            hdmi_eld_changed(melem, 0);
         }
-
-        snd_hctl_elem_set_callback_private(hctl_elem, u);
-        snd_hctl_elem_set_callback(hctl_elem, hdmi_eld_changed);
-        hdmi_eld_changed(hctl_elem, 0);
+        else
+            pa_log_debug("No ELD device found for port %s.", port->name);
     }
 }
 
@@ -501,17 +502,17 @@ static void init_jacks(struct userdata *
     u->mixer_fdl = pa_alsa_fdlist_new();
 
     u->mixer_handle = pa_alsa_open_mixer(u->alsa_card_index, NULL, 
&u->hctl_handle);
-    if (u->mixer_handle && pa_alsa_fdlist_set_handle(u->mixer_fdl, NULL, 
u->hctl_handle, u->core->mainloop) >= 0) {
+    if (u->mixer_handle && pa_alsa_fdlist_set_handle(u->mixer_fdl, 
u->mixer_handle, NULL, u->core->mainloop) >= 0) {
         PA_HASHMAP_FOREACH(jack, u->jacks, state) {
-            jack->hctl_elem = pa_alsa_find_jack(u->hctl_handle, 
jack->alsa_name);
-            if (!jack->hctl_elem) {
+            jack->melem = pa_alsa_mixer_find(u->mixer_handle, jack->alsa_name, 
0);
+            if (!jack->melem) {
                 pa_log_warn("Jack '%s' seems to have disappeared.", 
jack->alsa_name);
                 jack->has_control = false;
                 continue;
             }
-            snd_hctl_elem_set_callback_private(jack->hctl_elem, u);
-            snd_hctl_elem_set_callback(jack->hctl_elem, report_jack_state);
-            report_jack_state(jack->hctl_elem, 0);
+            snd_mixer_elem_set_callback(jack->melem, report_jack_state);
+            snd_mixer_elem_set_callback_private(jack->melem, u);
+            report_jack_state(jack->melem, 0);
         }
 
     } else
++++++ 0020-alsa-Remove-unnecessary-hctl-handles-being-passed-ar.patch ++++++
>From 300a5e3ed70064c296e09bc4e40531f3257154c5 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Mon, 1 Sep 2014 15:58:22 +0200
Subject: [PATCH] alsa: Remove unnecessary hctl handles being passed around

Now that we have switched to using the mixer handle only,
there is no use for sending hctl handles around.

Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/alsa-mixer.c       |   11 +++----
 src/modules/alsa/alsa-mixer.h       |    4 +-
 src/modules/alsa/alsa-sink.c        |    6 +--
 src/modules/alsa/alsa-source.c      |    6 +--
 src/modules/alsa/alsa-ucm.c         |    7 +---
 src/modules/alsa/alsa-util.c        |   56 ++++++------------------------------
 src/modules/alsa/alsa-util.h        |    7 +---
 src/modules/alsa/module-alsa-card.c |    9 ++---
 8 files changed, 30 insertions(+), 76 deletions(-)

--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -2614,7 +2614,7 @@ static void path_create_settings(pa_alsa
     element_create_settings(p->elements, NULL);
 }
 
-int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, snd_hctl_t *hctl, bool 
ignore_dB) {
+int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, bool ignore_dB) {
     pa_alsa_element *e;
     pa_alsa_jack *j;
     double min_dB[PA_CHANNEL_POSITION_MAX], max_dB[PA_CHANNEL_POSITION_MAX];
@@ -3808,7 +3808,6 @@ static void mapping_paths_probe(pa_alsa_
     snd_pcm_t *pcm_handle;
     pa_alsa_path_set *ps;
     snd_mixer_t *mixer_handle;
-    snd_hctl_t *hctl_handle;
 
     if (direction == PA_ALSA_DIRECTION_OUTPUT) {
         if (m->output_path_set)
@@ -3827,15 +3826,15 @@ static void mapping_paths_probe(pa_alsa_
 
     pa_assert(pcm_handle);
 
-    mixer_handle = pa_alsa_open_mixer_for_pcm(pcm_handle, NULL, &hctl_handle);
-    if (!mixer_handle || !hctl_handle) {
-         /* Cannot open mixer, remove all entries */
+    mixer_handle = pa_alsa_open_mixer_for_pcm(pcm_handle, NULL);
+    if (!mixer_handle) {
+        /* Cannot open mixer, remove all entries */
         pa_hashmap_remove_all(ps->paths);
         return;
     }
 
     PA_HASHMAP_FOREACH(p, ps->paths, state) {
-        if (pa_alsa_path_probe(p, mixer_handle, hctl_handle, 
m->profile_set->ignore_dB) < 0) {
+        if (pa_alsa_path_probe(p, mixer_handle, m->profile_set->ignore_dB) < 
0) {
             pa_hashmap_remove(ps->paths, p);
         }
     }
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -226,7 +226,7 @@ void pa_alsa_element_dump(pa_alsa_elemen
 
 pa_alsa_path *pa_alsa_path_new(const char *paths_dir, const char *fname, 
pa_alsa_direction_t direction);
 pa_alsa_path *pa_alsa_path_synthesize(const char *element, pa_alsa_direction_t 
direction);
-int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, snd_hctl_t *hctl, bool 
ignore_dB);
+int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, bool ignore_dB);
 void pa_alsa_path_dump(pa_alsa_path *p);
 int pa_alsa_path_get_volume(pa_alsa_path *p, snd_mixer_t *m, const 
pa_channel_map *cm, pa_cvolume *v);
 int pa_alsa_path_get_mute(pa_alsa_path *path, snd_mixer_t *m, bool *muted);
@@ -335,7 +335,7 @@ void pa_alsa_profile_set_free(pa_alsa_pr
 void pa_alsa_profile_set_dump(pa_alsa_profile_set *s);
 void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *s);
 
-snd_mixer_t *pa_alsa_open_mixer_for_pcm(snd_pcm_t *pcm, char **ctl_device, 
snd_hctl_t **hctl);
+snd_mixer_t *pa_alsa_open_mixer_for_pcm(snd_pcm_t *pcm, char **ctl_device);
 
 pa_alsa_fdlist *pa_alsa_fdlist_new(void);
 void pa_alsa_fdlist_free(pa_alsa_fdlist *fdl);
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -1886,12 +1886,10 @@ static void set_sink_name(pa_sink_new_da
 }
 
 static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const 
char *element, bool ignore_dB) {
-    snd_hctl_t *hctl;
-
     if (!mapping && !element)
         return;
 
-    if (!(u->mixer_handle = pa_alsa_open_mixer_for_pcm(u->pcm_handle, 
&u->control_device, &hctl))) {
+    if (!(u->mixer_handle = pa_alsa_open_mixer_for_pcm(u->pcm_handle, 
&u->control_device))) {
         pa_log_info("Failed to find a working mixer device.");
         return;
     }
@@ -1901,7 +1899,7 @@ static void find_mixer(struct userdata *
         if (!(u->mixer_path = pa_alsa_path_synthesize(element, 
PA_ALSA_DIRECTION_OUTPUT)))
             goto fail;
 
-        if (pa_alsa_path_probe(u->mixer_path, u->mixer_handle, hctl, 
ignore_dB) < 0)
+        if (pa_alsa_path_probe(u->mixer_path, u->mixer_handle, ignore_dB) < 0)
             goto fail;
 
         pa_log_debug("Probed mixer path %s:", u->mixer_path->name);
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1604,12 +1604,10 @@ static void set_source_name(pa_source_ne
 }
 
 static void find_mixer(struct userdata *u, pa_alsa_mapping *mapping, const 
char *element, bool ignore_dB) {
-    snd_hctl_t *hctl;
-
     if (!mapping && !element)
         return;
 
-    if (!(u->mixer_handle = pa_alsa_open_mixer_for_pcm(u->pcm_handle, 
&u->control_device, &hctl))) {
+    if (!(u->mixer_handle = pa_alsa_open_mixer_for_pcm(u->pcm_handle, 
&u->control_device))) {
         pa_log_info("Failed to find a working mixer device.");
         return;
     }
@@ -1619,7 +1617,7 @@ static void find_mixer(struct userdata *
         if (!(u->mixer_path = pa_alsa_path_synthesize(element, 
PA_ALSA_DIRECTION_INPUT)))
             goto fail;
 
-        if (pa_alsa_path_probe(u->mixer_path, u->mixer_handle, hctl, 
ignore_dB) < 0)
+        if (pa_alsa_path_probe(u->mixer_path, u->mixer_handle, ignore_dB) < 0)
             goto fail;
 
         pa_log_debug("Probed mixer path %s:", u->mixer_path->name);
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -1426,21 +1426,20 @@ static void profile_finalize_probing(pa_
 static void ucm_mapping_jack_probe(pa_alsa_mapping *m) {
     snd_pcm_t *pcm_handle;
     snd_mixer_t *mixer_handle;
-    snd_hctl_t *hctl_handle;
     pa_alsa_ucm_mapping_context *context = &m->ucm_context;
     pa_alsa_ucm_device *dev;
     uint32_t idx;
 
     pcm_handle = m->direction == PA_ALSA_DIRECTION_OUTPUT ? m->output_pcm : 
m->input_pcm;
-    mixer_handle = pa_alsa_open_mixer_for_pcm(pcm_handle, NULL, &hctl_handle);
-    if (!mixer_handle || !hctl_handle)
+    mixer_handle = pa_alsa_open_mixer_for_pcm(pcm_handle, NULL);
+    if (!mixer_handle)
         return;
 
     PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) {
         pa_alsa_jack *jack;
         jack = m->direction == PA_ALSA_DIRECTION_OUTPUT ? dev->output_jack : 
dev->input_jack;
         pa_assert (jack);
-        jack->has_control = pa_alsa_find_jack(hctl_handle, jack->alsa_name) != 
NULL;
+        jack->has_control = pa_alsa_mixer_find(mixer_handle, jack->alsa_name, 
0) != NULL;
         pa_log_info("UCM jack %s has_control=%d", jack->name, 
jack->has_control);
     }
 
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -1476,30 +1476,6 @@ snd_mixer_elem_t *pa_alsa_mixer_find(snd
     return NULL;
 }
 
-snd_hctl_elem_t* pa_alsa_find_jack(snd_hctl_t *hctl, const char* jack_name) {
-    snd_ctl_elem_id_t *id;
-
-    snd_ctl_elem_id_alloca(&id);
-    snd_ctl_elem_id_clear(id);
-    snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_CARD);
-    snd_ctl_elem_id_set_name(id, jack_name);
-
-    return snd_hctl_find_elem(hctl, id);
-}
-
-snd_hctl_elem_t* pa_alsa_find_eld_ctl(snd_hctl_t *hctl, int device) {
-    snd_ctl_elem_id_t *id;
-
-    /* See if we can find the ELD control */
-    snd_ctl_elem_id_alloca(&id);
-    snd_ctl_elem_id_clear(id);
-    snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM);
-    snd_ctl_elem_id_set_name(id, "ELD");
-    snd_ctl_elem_id_set_device(id, device);
-
-    return snd_hctl_find_elem(hctl, id);
-}
-
 static int mixer_class_compare(const snd_mixer_elem_t *c1, const 
snd_mixer_elem_t *c2)
 {
     /* Dummy compare function */
@@ -1544,7 +1520,7 @@ static int mixer_class_event(snd_mixer_c
     return 0;
 }
 
-static int prepare_mixer(snd_mixer_t *mixer, const char *dev, snd_hctl_t 
**hctl) {
+static int prepare_mixer(snd_mixer_t *mixer, const char *dev) {
     int err;
     snd_mixer_class_t *class;
 
@@ -1556,13 +1532,6 @@ static int prepare_mixer(snd_mixer_t *mi
         return -1;
     }
 
-    /* Note: The hctl handle returned should not be freed.
-       It is closed/freed by alsa-lib on snd_mixer_close/free */
-    if (hctl && (err = snd_mixer_get_hctl(mixer, dev, hctl)) < 0) {
-        pa_log_info("Unable to get hctl of mixer %s: %s", dev, 
pa_alsa_strerror(err));
-        return -1;
-    }
-
     if (snd_mixer_class_malloc(&class)) {
         pa_log_info("Failed to allocate mixer class for %s", dev);
         return -1;
@@ -1590,7 +1559,7 @@ static int prepare_mixer(snd_mixer_t *mi
     return 0;
 }
 
-snd_mixer_t *pa_alsa_open_mixer(int alsa_card_index, char **ctl_device, 
snd_hctl_t **hctl) {
+snd_mixer_t *pa_alsa_open_mixer(int alsa_card_index, char **ctl_device) {
     int err;
     snd_mixer_t *m;
     char *md;
@@ -1604,7 +1573,7 @@ snd_mixer_t *pa_alsa_open_mixer(int alsa
 
     /* Then, try by card index */
     md = pa_sprintf_malloc("hw:%i", alsa_card_index);
-    if (prepare_mixer(m, md, hctl) >= 0) {
+    if (prepare_mixer(m, md) >= 0) {
 
         if (ctl_device)
             *ctl_device = md;
@@ -1620,7 +1589,7 @@ snd_mixer_t *pa_alsa_open_mixer(int alsa
     return NULL;
 }
 
-snd_mixer_t *pa_alsa_open_mixer_for_pcm(snd_pcm_t *pcm, char **ctl_device, 
snd_hctl_t **hctl) {
+snd_mixer_t *pa_alsa_open_mixer_for_pcm(snd_pcm_t *pcm, char **ctl_device) {
     int err;
     snd_mixer_t *m;
     const char *dev;
@@ -1636,7 +1605,7 @@ snd_mixer_t *pa_alsa_open_mixer_for_pcm(
 
     /* First, try by name */
     if ((dev = snd_pcm_name(pcm)))
-        if (prepare_mixer(m, dev, hctl) >= 0) {
+        if (prepare_mixer(m, dev) >= 0) {
             if (ctl_device)
                 *ctl_device = pa_xstrdup(dev);
 
@@ -1653,7 +1622,7 @@ snd_mixer_t *pa_alsa_open_mixer_for_pcm(
             md = pa_sprintf_malloc("hw:%i", card_idx);
 
             if (!dev || !pa_streq(dev, md))
-                if (prepare_mixer(m, md, hctl) >= 0) {
+                if (prepare_mixer(m, md) >= 0) {
 
                     if (ctl_device)
                         *ctl_device = md;
@@ -1671,25 +1640,19 @@ snd_mixer_t *pa_alsa_open_mixer_for_pcm(
     return NULL;
 }
 
-int pa_alsa_get_hdmi_eld(snd_hctl_t *hctl, int device, pa_hdmi_eld *eld) {
+int pa_alsa_get_hdmi_eld(snd_hctl_elem_t *elem, pa_hdmi_eld *eld) {
 
     /* The ELD format is specific to HDA Intel sound cards and defined in the
        HDA specification: 
http://www.intel.com/content/www/us/en/standards/high-definition-audio-specification.html
 */
     int err;
-    snd_hctl_elem_t *elem;
     snd_ctl_elem_info_t *info;
     snd_ctl_elem_value_t *value;
     uint8_t *elddata;
     unsigned int eldsize, mnl;
+    unsigned int device;
 
     pa_assert(eld != NULL);
-
-    /* See if we can find the ELD control */
-    elem = pa_alsa_find_eld_ctl(hctl, device);
-    if (elem == NULL) {
-        pa_log_debug("No ELD info control found (for device=%d)", device);
-        return -1;
-    }
+    pa_assert(elem != NULL);
 
     /* Does it have any contents? */
     snd_ctl_elem_info_alloca(&info);
@@ -1700,6 +1663,7 @@ int pa_alsa_get_hdmi_eld(snd_hctl_t *hct
         return -1;
     }
 
+    device = snd_hctl_elem_get_device(elem);
     eldsize = snd_ctl_elem_info_get_count(info);
     elddata = (unsigned char *) snd_ctl_elem_value_get_bytes(value);
     if (elddata == NULL || eldsize == 0) {
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -142,18 +142,15 @@ const char* pa_alsa_strerror(int errnum)
 
 bool pa_alsa_may_tsched(bool want);
 
-snd_hctl_elem_t* pa_alsa_find_jack(snd_hctl_t *hctl, const char* jack_name);
-snd_hctl_elem_t* pa_alsa_find_eld_ctl(snd_hctl_t *hctl, int device);
-
 snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, const char *name, 
unsigned int device);
 
-snd_mixer_t *pa_alsa_open_mixer(int alsa_card_index, char **ctl_device, 
snd_hctl_t **hctl);
+snd_mixer_t *pa_alsa_open_mixer(int alsa_card_index, char **ctl_device);
 
 typedef struct pa_hdmi_eld pa_hdmi_eld;
 struct pa_hdmi_eld {
     char monitor_name[17];
 };
 
-int pa_alsa_get_hdmi_eld(snd_hctl_t *hctl, int device, pa_hdmi_eld *eld);
+int pa_alsa_get_hdmi_eld(snd_hctl_elem_t *elem, pa_hdmi_eld *eld);
 
 #endif
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -111,7 +111,6 @@ struct userdata {
     int alsa_card_index;
 
     snd_mixer_t *mixer_handle;
-    snd_hctl_t *hctl_handle;
     pa_hashmap *jacks;
     pa_alsa_fdlist *mixer_fdl;
 
@@ -422,7 +421,7 @@ static int hdmi_eld_changed(snd_mixer_el
         return 0;
     }
 
-    if (pa_alsa_get_hdmi_eld(u->hctl_handle, device, &eld) < 0)
+    if (pa_alsa_get_hdmi_eld(elem, &eld) < 0)
         memset(&eld, 0, sizeof(eld));
 
     old_monitor_name = pa_proplist_gets(p->proplist, 
PA_PROP_DEVICE_PRODUCT_NAME);
@@ -444,7 +443,7 @@ static void init_eld_ctls(struct userdat
     void *state;
     pa_device_port *port;
 
-    if (!u->hctl_handle)
+    if (!u->mixer_handle)
         return;
 
     PA_HASHMAP_FOREACH(port, u->card->ports, state) {
@@ -501,7 +500,7 @@ static void init_jacks(struct userdata *
 
     u->mixer_fdl = pa_alsa_fdlist_new();
 
-    u->mixer_handle = pa_alsa_open_mixer(u->alsa_card_index, NULL, 
&u->hctl_handle);
+    u->mixer_handle = pa_alsa_open_mixer(u->alsa_card_index, NULL);
     if (u->mixer_handle && pa_alsa_fdlist_set_handle(u->mixer_fdl, 
u->mixer_handle, NULL, u->core->mainloop) >= 0) {
         PA_HASHMAP_FOREACH(jack, u->jacks, state) {
             jack->melem = pa_alsa_mixer_find(u->mixer_handle, jack->alsa_name, 
0);
@@ -516,7 +515,7 @@ static void init_jacks(struct userdata *
         }
 
     } else
-        pa_log("Failed to open hctl/mixer for jack detection");
+        pa_log("Failed to open mixer for jack detection");
 
 }
 
++++++ 0021-alsa-mixer-Merge-analog-output-desktop-speaker-with-.patch ++++++
>From 052316e4195cc01c6b13ce9e21724cb7c25aad82 Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaski...@linux.intel.com>
Date: Mon, 27 Oct 2014 13:20:01 +0200
Subject: [PATCH] alsa-mixer: Merge analog-output-desktop-speaker with
 analog-output-speaker(-always)

According to David[1], it's unlikely that there are any sound cards
that would have separate "speaker" and "desktop speaker" paths, so
let's remove the unnecessary distinction.

[1] 
http://thread.gmane.org/gmane.comp.audio.pulseaudio.general/20915/focus=21193
---
 src/Makefile.am                                                    |    1 
 src/modules/alsa/mixer/paths/analog-output-desktop-speaker.conf    |  102 
----------
 src/modules/alsa/mixer/paths/analog-output-speaker-always.conf     |    6 
 src/modules/alsa/mixer/paths/analog-output-speaker.conf            |    7 
 src/modules/alsa/mixer/profile-sets/default.conf                   |   16 -
 src/modules/alsa/mixer/profile-sets/force-speaker-and-int-mic.conf |   16 -
 src/modules/alsa/mixer/profile-sets/force-speaker.conf             |   16 -
 7 files changed, 33 insertions(+), 131 deletions(-)
 delete mode 100644 
src/modules/alsa/mixer/paths/analog-output-desktop-speaker.conf

--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1236,7 +1236,6 @@ dist_alsapaths_DATA = \
                modules/alsa/mixer/paths/analog-output-speaker.conf \
                modules/alsa/mixer/paths/analog-output-speaker-always.conf \
                modules/alsa/mixer/paths/analog-output.conf.common \
-               modules/alsa/mixer/paths/analog-output-desktop-speaker.conf \
                modules/alsa/mixer/paths/analog-output-headphones.conf \
                modules/alsa/mixer/paths/analog-output-headphones-2.conf \
                modules/alsa/mixer/paths/analog-output-lineout.conf \
--- a/src/modules/alsa/mixer/paths/analog-output-desktop-speaker.conf
+++ /dev/null
@@ -1,102 +0,0 @@
-# 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.
-
-; Path for mixers that have a 'Desktop Speaker' control
-;
-; See analog-output.conf.common for an explanation on the directives
-
-[General]
-priority = 101
-description-key = analog-output-speaker
-
-[Properties]
-device.icon_name = audio-speakers
-
-[Element Hardware Master]
-switch = mute
-volume = merge
-override-map.1 = all
-override-map.2 = all-left,all-right
-
-[Element Master]
-switch = mute
-volume = merge
-override-map.1 = all
-override-map.2 = all-left,all-right
-
-[Element Master Mono]
-switch = off
-volume = off
-
-; This profile path is intended to control the desktop speaker, not
-; the headphones. But it should not hurt if we leave the headphone
-; jack enabled nonetheless.
-[Element Headphone]
-switch = mute
-volume = zero
-
-[Element Headphone2]
-switch = mute
-volume = zero
-
-[Element Speaker]
-switch = off
-volume = off
-
-[Element Desktop Speaker]
-required = any
-switch = mute
-volume = merge
-override-map.1 = all
-override-map.2 = all-left,all-right
-
-[Element Front]
-switch = mute
-volume = merge
-override-map.1 = all-front
-override-map.2 = front-left,front-right
-
-[Element Rear]
-switch = mute
-volume = merge
-override-map.1 = all-rear
-override-map.2 = rear-left,rear-right
-
-[Element Surround]
-switch = mute
-volume = merge
-override-map.1 = all-rear
-override-map.2 = rear-left,rear-right
-
-[Element Side]
-switch = mute
-volume = merge
-override-map.1 = all-side
-override-map.2 = side-left,side-right
-
-[Element Center]
-switch = mute
-volume = merge
-override-map.1 = all-center
-override-map.2 = all-center,all-center
-
-[Element LFE]
-switch = mute
-volume = merge
-override-map.1 = lfe
-override-map.2 = lfe,lfe
-
-.include analog-output.conf.common
--- a/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf
@@ -68,8 +68,10 @@ override-map.1 = all
 override-map.2 = all-left,all-right
 
 [Element Desktop Speaker]
-switch = off
-volume = off
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
 
 [Element Front]
 switch = mute
--- a/src/modules/alsa/mixer/paths/analog-output-speaker.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-speaker.conf
@@ -81,8 +81,11 @@ override-map.1 = all
 override-map.2 = all-left,all-right
 
 [Element Desktop Speaker]
-switch = off
-volume = off
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
 
 [Element Front]
 switch = mute
--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -105,49 +105,49 @@ auto-profiles = yes
 [Mapping analog-mono]
 device-strings = hw:%f
 channel-map = mono
-paths-output = analog-output analog-output-lineout analog-output-speaker 
analog-output-desktop-speaker analog-output-headphones 
analog-output-headphones-2 analog-output-mono
+paths-output = analog-output analog-output-lineout analog-output-speaker 
analog-output-headphones analog-output-headphones-2 analog-output-mono
 paths-input = analog-input-front-mic analog-input-rear-mic 
analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic 
analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner 
analog-input-fm analog-input-mic-line analog-input-headset-mic
 priority = 2
 
 [Mapping analog-stereo]
 device-strings = front:%f hw:%f
 channel-map = left,right
-paths-output = analog-output analog-output-lineout analog-output-speaker 
analog-output-desktop-speaker analog-output-headphones 
analog-output-headphones-2
+paths-output = analog-output analog-output-lineout analog-output-speaker 
analog-output-headphones analog-output-headphones-2
 paths-input = analog-input-front-mic analog-input-rear-mic 
analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic 
analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner 
analog-input-fm analog-input-mic-line analog-input-headphone-mic 
analog-input-headset-mic
 priority = 10
 
 [Mapping analog-surround-21]
 device-strings = surround21:%f
 channel-map = front-left,front-right,lfe
-paths-output = analog-output analog-output-speaker 
analog-output-desktop-speaker
+paths-output = analog-output analog-output-speaker
 priority = 8
 direction = output
 
 [Mapping analog-surround-40]
 device-strings = surround40:%f
 channel-map = front-left,front-right,rear-left,rear-right
-paths-output = analog-output analog-output-lineout analog-output-speaker 
analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker
 priority = 7
 direction = output
 
 [Mapping analog-surround-41]
 device-strings = surround41:%f
 channel-map = front-left,front-right,rear-left,rear-right,lfe
-paths-output = analog-output analog-output-lineout analog-output-speaker 
analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker
 priority = 8
 direction = output
 
 [Mapping analog-surround-50]
 device-strings = surround50:%f
 channel-map = front-left,front-right,rear-left,rear-right,front-center
-paths-output = analog-output analog-output-lineout analog-output-speaker 
analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker
 priority = 7
 direction = output
 
 [Mapping analog-surround-51]
 device-strings = surround51:%f
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
-paths-output = analog-output analog-output-lineout analog-output-speaker 
analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker
 priority = 8
 direction = output
 
@@ -155,7 +155,7 @@ direction = output
 device-strings = surround71:%f
 channel-map = 
front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
 description = Analog Surround 7.1
-paths-output = analog-output analog-output-lineout analog-output-speaker 
analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker
 priority = 7
 direction = output
 
--- a/src/modules/alsa/mixer/profile-sets/force-speaker-and-int-mic.conf
+++ b/src/modules/alsa/mixer/profile-sets/force-speaker-and-int-mic.conf
@@ -24,49 +24,49 @@ auto-profiles = yes
 [Mapping analog-mono]
 device-strings = hw:%f
 channel-map = mono
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker 
analog-output-headphones analog-output-headphones-2 analog-output-mono
+paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-headphones 
analog-output-headphones-2 analog-output-mono
 paths-input = analog-input-front-mic analog-input-rear-mic 
analog-input-internal-mic-always analog-input-dock-mic analog-input 
analog-input-mic analog-input-linein analog-input-aux analog-input-video 
analog-input-tvtuner analog-input-fm analog-input-mic-line
 priority = 1
 
 [Mapping analog-stereo]
 device-strings = front:%f hw:%f
 channel-map = left,right
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker 
analog-output-headphones analog-output-headphones-2 analog-output-mono
+paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-headphones 
analog-output-headphones-2 analog-output-mono
 paths-input = analog-input-front-mic analog-input-rear-mic 
analog-input-internal-mic-always analog-input-dock-mic analog-input 
analog-input-mic analog-input-linein analog-input-aux analog-input-video 
analog-input-tvtuner analog-input-fm analog-input-mic-line
 priority = 10
 
 [Mapping analog-surround-21]
 device-strings = surround21:%f
 channel-map = front-left,front-right,lfe
-paths-output = analog-output analog-output-speaker-always 
analog-output-desktop-speaker
+paths-output = analog-output analog-output-speaker-always
 priority = 8
 direction = output
 
 [Mapping analog-surround-40]
 device-strings = surround40:%f
 channel-map = front-left,front-right,rear-left,rear-right
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 7
 direction = output
 
 [Mapping analog-surround-41]
 device-strings = surround41:%f
 channel-map = front-left,front-right,rear-left,rear-right,lfe
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 8
 direction = output
 
 [Mapping analog-surround-50]
 device-strings = surround50:%f
 channel-map = front-left,front-right,rear-left,rear-right,front-center
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 7
 direction = output
 
 [Mapping analog-surround-51]
 device-strings = surround51:%f
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 8
 direction = output
 
@@ -74,7 +74,7 @@ direction = output
 device-strings = surround71:%f
 channel-map = 
front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
 description = Analog Surround 7.1
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 7
 direction = output
 
--- a/src/modules/alsa/mixer/profile-sets/force-speaker.conf
+++ b/src/modules/alsa/mixer/profile-sets/force-speaker.conf
@@ -23,49 +23,49 @@ auto-profiles = yes
 [Mapping analog-mono]
 device-strings = hw:%f
 channel-map = mono
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker 
analog-output-headphones analog-output-headphones-2 analog-output-mono
+paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-headphones 
analog-output-headphones-2 analog-output-mono
 paths-input = analog-input-front-mic analog-input-rear-mic 
analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic 
analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner 
analog-input-fm analog-input-mic-line
 priority = 1
 
 [Mapping analog-stereo]
 device-strings = front:%f hw:%f
 channel-map = left,right
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker 
analog-output-headphones analog-output-headphones-2 analog-output-mono
+paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-headphones 
analog-output-headphones-2 analog-output-mono
 paths-input = analog-input-front-mic analog-input-rear-mic 
analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic 
analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner 
analog-input-fm analog-input-mic-line
 priority = 10
 
 [Mapping analog-surround-21]
 device-strings = surround21:%f
 channel-map = front-left,front-right,lfe
-paths-output = analog-output analog-output-speaker-always 
analog-output-desktop-speaker
+paths-output = analog-output analog-output-speaker-always
 priority = 8
 direction = output
 
 [Mapping analog-surround-40]
 device-strings = surround40:%f
 channel-map = front-left,front-right,rear-left,rear-right
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 7
 direction = output
 
 [Mapping analog-surround-41]
 device-strings = surround41:%f
 channel-map = front-left,front-right,rear-left,rear-right,lfe
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 8
 direction = output
 
 [Mapping analog-surround-50]
 device-strings = surround50:%f
 channel-map = front-left,front-right,rear-left,rear-right,front-center
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 7
 direction = output
 
 [Mapping analog-surround-51]
 device-strings = surround51:%f
 channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 8
 direction = output
 
@@ -73,7 +73,7 @@ direction = output
 device-strings = surround71:%f
 channel-map = 
front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
 description = Analog Surround 7.1
-paths-output = analog-output analog-output-lineout 
analog-output-speaker-always analog-output-desktop-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 7
 direction = output
 
++++++ 0024-alsa-mixer-Ignore-some-elements-in-the-analog-output.patch ++++++
>From 717834086c57667823a34d76357a572f43e5313b Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaski...@linux.intel.com>
Date: Mon, 27 Oct 2014 13:00:00 +0200
Subject: [PATCH] alsa-mixer: Ignore some elements in the analog-output path

The analog-output path should be suppressed when there are more
specific paths available. Currently that usually doesn't happen. The
suppression can be done with the path subset detection, and this patch
makes that work (another approach would be to mark the elements as
required-absent, like analog-input does, but I like the subset
suppression more, because it requires less stuff in the configuration
files). The problem with listing the now-removed elements in
analog-output.conf was that if the sound card had e.g. a Speaker
element, then the switch behaviour was different between analog-output
and analog-output-speakers, so analog-output was not considered a
subset of analog-output-speakers.

BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=74609
---
 src/modules/alsa/mixer/paths/analog-output.conf |   30 ------------------------
 1 file changed, 30 deletions(-)

--- a/src/modules/alsa/mixer/paths/analog-output.conf
+++ b/src/modules/alsa/mixer/paths/analog-output.conf
@@ -22,14 +22,6 @@
 [General]
 priority = 99
 
-[Jack Line Out]
-state.plugged = unknown
-state.unplugged = unknown
-
-[Jack Line Out Phantom]
-state.plugged = unknown
-state.unplugged = unknown
-
 [Element Hardware Master]
 switch = mute
 volume = merge
@@ -46,28 +38,6 @@ override-map.2 = all-left,all-right
 switch = off
 volume = off
 
-[Element Line HP Swap]
-switch = off
-
-; This profile path is intended to control the default output, not the
-; headphones. But it should not hurt if we leave the headphone jack
-; enabled nonetheless.
-[Element Headphone]
-switch = mute
-volume = zero
-
-[Element Headphone2]
-switch = mute
-volume = zero
-
-[Element Speaker]
-switch = mute
-volume = off
-
-[Element Desktop Speaker]
-switch = mute
-volume = off
-
 [Element Front]
 switch = mute
 volume = merge
++++++ 0025-alsa-mixer-Disable-line-out-if-headphone-jack-is-plu.patch ++++++
>From 66f97c35bda9524985b8d34d9a7dbfa9b1359df5 Mon Sep 17 00:00:00 2001
From: Sjoerd Simons <sjo...@luon.net>
Date: Fri, 31 Oct 2014 22:01:28 +0100
Subject: [PATCH] alsa-mixer: Disable line-out if headphone jack is plugged

Line-out gets muted when headphones are plugged in on HDA cards, encode
this in the line-out path so pulse can match that state.
---
 src/modules/alsa/mixer/paths/analog-output-lineout.conf |    4 ++++
 1 file changed, 4 insertions(+)

--- a/src/modules/alsa/mixer/paths/analog-output-lineout.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-lineout.conf
@@ -26,6 +26,10 @@ state.plugged = unknown
 state.unplugged = unknown
 required-any = any
 
+[Jack Headphone]
+state.plugged = no
+state.unplugged = unknown
+
 [Jack Line Out Front]
 required-any = any
 
++++++ 0026-alsa-mixer-Add-support-for-Headphone-LO-and-Speaker-.patch ++++++
>From aec811798cd883a454b9b5cd82c77831906bbd2d Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Mon, 20 Oct 2014 13:34:49 +0200
Subject: [PATCH] alsa-mixer: Add support for "Headphone+LO" and "Speaker+LO"

These two control names are currently being added to the HDA driver,
so let's support them in PulseAudio as well.

Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/mixer/paths/analog-output-headphones-2.conf   |    8 +++++
 src/modules/alsa/mixer/paths/analog-output-headphones.conf     |   11 +++++++
 src/modules/alsa/mixer/paths/analog-output-lineout.conf        |   14 
++++++++++
 src/modules/alsa/mixer/paths/analog-output-mono.conf           |   10 +++++++
 src/modules/alsa/mixer/paths/analog-output-speaker-always.conf |   10 +++++++
 src/modules/alsa/mixer/paths/analog-output-speaker.conf        |   11 +++++++
 6 files changed, 64 insertions(+)

--- a/src/modules/alsa/mixer/paths/analog-output-headphones-2.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-headphones-2.conf
@@ -48,6 +48,14 @@ volume = off
 switch = mute
 volume = zero
 
+[Element Headphone+LO]
+switch = mute
+volume = zero
+
+[Element Speaker+LO]
+switch = off
+volume = off
+
 [Element Headphone2]
 required = any
 switch = mute
--- a/src/modules/alsa/mixer/paths/analog-output-headphones.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-headphones.conf
@@ -69,6 +69,17 @@ override-map.2 = all-left,all-right
 switch = off
 volume = off
 
+[Element Speaker+LO]
+switch = off
+volume = off
+
+[Element Headphone+LO]
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
 [Element Headphone]
 required-any = any
 switch = mute
--- a/src/modules/alsa/mixer/paths/analog-output-lineout.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-lineout.conf
@@ -80,6 +80,20 @@ volume = merge
 override-map.1 = all
 override-map.2 = all-left,all-right
 
+[Element Speaker+LO]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+required-any = any
+
+[Element Headphone+LO]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+required-any = any
+
 [Element Master Mono]
 switch = off
 volume = off
--- a/src/modules/alsa/mixer/paths/analog-output-mono.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-mono.conf
@@ -45,6 +45,10 @@ override-map.2 = all-left,all-right
 switch = mute
 volume = zero
 
+[Element Headphone+LO]
+switch = mute
+volume = zero
+
 [Element Headphone2]
 switch = mute
 volume = zero
@@ -53,6 +57,12 @@ volume = zero
 switch = mute
 volume = merge
 override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Speaker+LO]
+switch = mute
+volume = merge
+override-map.1 = all
 override-map.2 = all-left,all-right
 
 [Element Desktop Speaker]
--- a/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf
@@ -61,6 +61,16 @@ volume = zero
 switch = mute
 volume = zero
 
+[Element Headphone+LO]
+switch = off
+volume = off
+
+[Element Speaker+LO]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
 [Element Speaker]
 switch = mute
 volume = merge
--- a/src/modules/alsa/mixer/paths/analog-output-speaker.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-speaker.conf
@@ -73,6 +73,17 @@ volume = off
 switch = off
 volume = off
 
+[Element Headphone+LO]
+switch = off
+volume = off
+
+[Element Speaker+LO]
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
 [Element Speaker]
 required-any = any
 switch = mute
++++++ 0029-Alsa-Correct-port-availability-with-multiple-jacks.patch ++++++
>From d5fec4ca7af9241d0c2ae17df40d0fb1c18c74a0 Mon Sep 17 00:00:00 2001
From: Sjoerd Simons <sjo...@luon.net>
Date: Sun, 16 Nov 2014 23:15:50 +0100
Subject: [PATCH] Alsa: Correct port availability with multiple jacks

In case there are two independent jacks for one port (e.g. Dock
Headphone Jack and Headphone Jack), the availability ends up being
incorrect if the first one was _NO (not plugged) and the second gets
_YES (plugged). Also pulse complains about the state being inconsistent
which isn't true.

Fix this by preferring more precise states (yes/no) over unknown and yes
over others. However in case a plugged jack makes the port unavailable
let that overrule everything else.
---
 src/modules/alsa/module-alsa-card.c |   25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -335,15 +335,26 @@ static void report_port_state(pa_device_
 
         cpa = jack->plugged_in ? jack->state_plugged : jack->state_unplugged;
 
-        /* "Yes" and "no" trumphs "unknown" if we have more than one jack */
-        if (cpa == PA_AVAILABLE_UNKNOWN)
-            continue;
+        if (cpa == PA_AVAILABLE_NO) {
+          /* If a plugged-in jack causes the availability to go to NO, it
+           * should override all other availability information (like a
+           * blacklist) so set and bail */
+          if (jack->plugged_in) {
+            pa = cpa;
+            break;
+          }
 
-        if ((cpa == PA_AVAILABLE_NO && pa == PA_AVAILABLE_YES) ||
-            (pa == PA_AVAILABLE_NO && cpa == PA_AVAILABLE_YES))
-            pa_log_warn("Availability of port '%s' is inconsistent!", p->name);
-        else
+          /* If the current availablility is unknown go the more precise no,
+           * but otherwise don't change state */
+          if (pa == PA_AVAILABLE_UNKNOWN)
             pa = cpa;
+        } else if (cpa == PA_AVAILABLE_YES) {
+          /* Output is available through at least one jack, so go to that
+           * level of availability. We still need to continue iterating through
+           * the jacks in case a jack is plugged in that forces the state to no
+           */
+          pa = cpa;
+        }
     }
 
     pa_device_port_set_available(p, pa);
++++++ 0032-alsa-util-fix-parenthesis-position-in-err-assignment.patch ++++++
>From 3e6ce485f090780f623a879ad6a8dfd85edf53c1 Mon Sep 17 00:00:00 2001
From: Boris Egorov <ego...@linux.com>
Date: Mon, 12 Jan 2015 23:52:10 +0600
Subject: [PATCH] alsa-util: fix parenthesis position in err assignment

Issue detected by CppCheck and PVS Studio
---
 src/modules/alsa/alsa-util.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -442,7 +442,7 @@ int pa_alsa_set_sw_params(snd_pcm_t *pcm
 
     snd_pcm_sw_params_alloca(&swparams);
 
-    if ((err = snd_pcm_sw_params_current(pcm, swparams) < 0)) {
+    if ((err = snd_pcm_sw_params_current(pcm, swparams)) < 0) {
         pa_log_warn("Unable to determine current swparams: %s\n", 
pa_alsa_strerror(err));
         return err;
     }
++++++ 0033-alsa-mixer-Mute-headphones-and-speakers-on-line-out-.patch ++++++
>From 9d0a5b5cb7ea3adc1b548a6e1e953ee20835e6b6 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Tue, 13 Jan 2015 11:28:16 +0100
Subject: [PATCH] alsa-mixer: Mute headphones and speakers on line out path

When line out path is active, we want to mute speakers for obvious
reasons, and headphones to avoid volume spikes.

Reported-by: TienFu Chen <tienfu.c...@canonical.com>
Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/mixer/paths/analog-output-lineout.conf |   17 +++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

--- a/src/modules/alsa/mixer/paths/analog-output-lineout.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-lineout.conf
@@ -102,23 +102,22 @@ volume = off
 switch = off
 required-any = any
 
-; This profile path is intended to control the default output, not the
-; headphones. But it should not hurt if we leave the headphone jack
-; enabled nonetheless.
+; This profile path is intended to control line out, let's mute headphones
+; else there will be a spike when plugging in headphones
 [Element Headphone]
-switch = mute
-volume = zero
+switch = off
+volume = off
 
 [Element Headphone2]
-switch = mute
-volume = zero
+switch = off
+volume = off
 
 [Element Speaker]
-switch = mute
+switch = off
 volume = off
 
 [Element Desktop Speaker]
-switch = mute
+switch = off
 volume = off
 
 [Element Front]
++++++ 0035-alsa-mixer-Add-lineout-to-surround21-mappings.patch ++++++
>From f75335f25c49b2d2ff26181902c4f6f90ae7cab6 Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaski...@linux.intel.com>
Date: Thu, 29 Jan 2015 13:53:08 +0200
Subject: [PATCH] alsa-mixer: Add lineout to surround21 mappings

This makes the analog-surround-21 mapping consistent with other
surround mappings. I'm not sure if this makes any practical
difference, though.
---
 src/modules/alsa/mixer/profile-sets/default.conf                   |    2 +-
 src/modules/alsa/mixer/profile-sets/force-speaker-and-int-mic.conf |    2 +-
 src/modules/alsa/mixer/profile-sets/force-speaker.conf             |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -119,7 +119,7 @@ priority = 10
 [Mapping analog-surround-21]
 device-strings = surround21:%f
 channel-map = front-left,front-right,lfe
-paths-output = analog-output analog-output-speaker
+paths-output = analog-output analog-output-lineout analog-output-speaker
 priority = 8
 direction = output
 
--- a/src/modules/alsa/mixer/profile-sets/force-speaker-and-int-mic.conf
+++ b/src/modules/alsa/mixer/profile-sets/force-speaker-and-int-mic.conf
@@ -38,7 +38,7 @@ priority = 10
 [Mapping analog-surround-21]
 device-strings = surround21:%f
 channel-map = front-left,front-right,lfe
-paths-output = analog-output analog-output-speaker-always
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 8
 direction = output
 
--- a/src/modules/alsa/mixer/profile-sets/force-speaker.conf
+++ b/src/modules/alsa/mixer/profile-sets/force-speaker.conf
@@ -37,7 +37,7 @@ priority = 10
 [Mapping analog-surround-21]
 device-strings = surround21:%f
 channel-map = front-left,front-right,lfe
-paths-output = analog-output analog-output-speaker-always
+paths-output = analog-output analog-output-lineout analog-output-speaker-always
 priority = 8
 direction = output
 
++++++ 0036-alsa-mixer-Make-speaker-unavailable-when-Line-Out-is.patch ++++++
>From 5cc3d4aa9dc93202f329afa48fbd4227f1f80156 Mon Sep 17 00:00:00 2001
From: David Henningsson <david.hennings...@canonical.com>
Date: Thu, 29 Jan 2015 10:24:35 -0500
Subject: [PATCH] alsa-mixer: Make speaker unavailable when Line Out is plugged
 in

ALSA mutes speaker when Line Out is plugged in by default, so
we should follow that convention.

Signed-off-by: David Henningsson <david.hennings...@canonical.com>
---
 src/modules/alsa/mixer/paths/analog-output-speaker-always.conf |    8 ++++++++
 src/modules/alsa/mixer/paths/analog-output-speaker.conf        |    8 ++++++++
 2 files changed, 16 insertions(+)

--- a/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-speaker-always.conf
@@ -34,6 +34,14 @@ state.unplugged = unknown
 state.plugged = no
 state.unplugged = unknown
 
+[Jack Line Out]
+state.plugged = no
+state.unplugged = unknown
+
+[Jack Line Out Front]
+state.plugged = no
+state.unplugged = unknown
+
 [Element Hardware Master]
 switch = mute
 volume = merge
--- a/src/modules/alsa/mixer/paths/analog-output-speaker.conf
+++ b/src/modules/alsa/mixer/paths/analog-output-speaker.conf
@@ -37,6 +37,14 @@ state.unplugged = unknown
 state.plugged = no
 state.unplugged = unknown
 
+[Jack Line Out]
+state.plugged = no
+state.unplugged = unknown
+
+[Jack Line Out Front]
+state.plugged = no
+state.unplugged = unknown
+
 [Jack Speaker Phantom]
 required-any = any
 state.plugged = unknown
++++++ 0037-alsa-Don-t-try-to-use-ELD-controls-with-UCM.patch ++++++
>From 82ec47898e77dca94a7d73e976363f745081d828 Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaski...@linux.intel.com>
Date: Sat, 7 Feb 2015 00:15:34 +0200
Subject: [PATCH] alsa: Don't try to use ELD controls with UCM

This fixes a crash that occurred when trying to access non-existent
port data. Doing this:

    pa_alsa_port_data *data = PA_DEVICE_PORT_DATA(port);

is not a good idea when using UCM, because in the UCM mode ports don't
have any data, so the data pointer points to some random memory.
---
 src/modules/alsa/module-alsa-card.c |    6 ++++++
 1 file changed, 6 insertions(+)

--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -457,6 +457,12 @@ static void init_eld_ctls(struct userdat
     if (!u->mixer_handle)
         return;
 
+    /* The code in this function expects ports to have a pa_alsa_port_data
+     * struct as their data, but in UCM mode ports don't have any data. Hence,
+     * the ELD controls can't currently be used in UCM mode. */
+    if (u->use_ucm)
+        return;
+
     PA_HASHMAP_FOREACH(port, u->card->ports, state) {
         pa_alsa_port_data *data = PA_DEVICE_PORT_DATA(port);
         snd_mixer_elem_t* melem;
++++++ 0038-sink-input-source-output-Fix-mute-saving.patch ++++++
>From cd2db42a6a462c4ad2441984466874a85fec9fbc Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaski...@linux.intel.com>
Date: Tue, 15 Apr 2014 10:59:03 +0300
Subject: [PATCH] sink-input, source-output: Fix mute saving

"i->save_muted = i->save_muted || mute" makes no sense. The intention
was most likely to use "save" instead of "mute" in the assignment.
This line originates from reverting the volume ramping code, commit
8401572fd534f10e07ed6a418e1399b1294d5596.

The idea of "i->save_muted |= save" is that even if the mute state
doesn't change, save_muted should still be updated, but only if the
transition is from "don't save" to "save".

Changing "!i->muted == !mute" to "mute == i->muted" is cosmetic only.
The rationale behind the old form was probably that when we still had
pa_bool_t, booleans could in theory be defined as int, so comparing
the values without the ! operator was not entirely safe. That's
unnecessary now that we use the standard bool type, which can only
have values 0 or 1.
---
 src/pulsecore/sink-input.c    |    4 ++--
 src/pulsecore/source-output.c |    4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -1414,8 +1414,8 @@ void pa_sink_input_set_mute(pa_sink_inpu
     pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 
-    if (!i->muted == !mute) {
-        i->save_muted = i->save_muted || mute;
+    if (mute == i->muted) {
+        i->save_muted |= save;
         return;
     }
 
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -1061,8 +1061,8 @@ void pa_source_output_set_mute(pa_source
     pa_assert_ctl_context();
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
 
-    if (!o->muted == !mute) {
-        o->save_muted = o->save_muted || mute;
+    if (mute == o->muted) {
+        o->save_muted |= save;
         return;
     }
 
++++++ 0039-sink-source-Return-early-from-set_mute.patch ++++++
>From 70441d40fb07b13cca85d08fe09c9ddb81eadaf0 Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaski...@linux.intel.com>
Date: Tue, 15 Apr 2014 13:56:05 +0300
Subject: [PATCH] sink, source: Return early from set_mute()

This avoids redundant set_mute() callback calls.

Some logging was added too.
---
 src/pulsecore/sink.c   |   13 +++++++++----
 src/pulsecore/source.c |   13 +++++++++----
 2 files changed, 18 insertions(+), 8 deletions(-)

--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -2233,16 +2233,21 @@ void pa_sink_set_mute(pa_sink *s, bool m
     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 */
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -1828,16 +1828,21 @@ void pa_source_set_mute(pa_source *s, bo
     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 */
++++++ 0040-sink-source-Allow-calling-set_mute-during-initializa.patch ++++++
>From 5f64ebdfc57f1a5728a7f84d9c69d3a815f467f1 Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <tanu.kaski...@linux.intel.com>
Date: Tue, 15 Apr 2014 13:56:07 +0300
Subject: [PATCH] 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.
---
 src/pulsecore/sink.c   |    4 +++-
 src/pulsecore/source.c |    4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -2230,7 +2230,6 @@ void pa_sink_set_mute(pa_sink *s, bool m
 
     pa_sink_assert_ref(s);
     pa_assert_ctl_context();
-    pa_assert(PA_SINK_IS_LINKED(s->state));
 
     old_muted = s->muted;
 
@@ -2245,6 +2244,9 @@ void pa_sink_set_mute(pa_sink *s, bool m
     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);
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -1825,7 +1825,6 @@ void pa_source_set_mute(pa_source *s, bo
 
     pa_source_assert_ref(s);
     pa_assert_ctl_context();
-    pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     old_muted = s->muted;
 
@@ -1840,6 +1839,9 @@ void pa_source_set_mute(pa_source *s, bo
     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);
++++++ baselibs.conf ++++++
libpulse0
  obsoletes "pulseaudio-libs-<targettype> <= <version>"
  provides "pulseaudio-libs-<targettype> = <version>"
libpulse-mainloop-glib0
++++++ default.pa-for-gdm ++++++
load-module module-device-restore
load-module module-card-restore
load-module module-udev-detect
load-module module-native-protocol-unix
load-module module-default-device-restore
load-module module-rescue-streams
load-module module-always-sink
load-module module-intended-roles
load-module module-suspend-on-idle
load-module module-console-kit
load-module module-position-event-sounds

++++++ disabled-start.diff ++++++
Index: src/daemon/start-pulseaudio-x11.in
===================================================================
--- src/daemon/start-pulseaudio-x11.in.orig
+++ src/daemon/start-pulseaudio-x11.in
@@ -19,6 +19,12 @@
 
 set -e
 
+. /etc/sysconfig/sound
+
+if [ x"$PULSEAUDIO_ENABLE" = x"no" ] || [ x"$PULSEAUDIO_SYSTEM" = x"yes" ] ; 
then
+    exit 1
+fi
+
 @PA_BINARY@ --start "$@"
 
 if [ x"$DISPLAY" != x ] ; then
Index: src/daemon/start-pulseaudio-kde.in
===================================================================
--- src/daemon/start-pulseaudio-kde.in.orig
+++ src/daemon/start-pulseaudio-kde.in
@@ -19,6 +19,12 @@
 
 set -e
 
+. /etc/sysconfig/sound
+
+if [ x"$PULSEAUDIO_ENABLE" = x"no" ] || [ x"$PULSEAUDIO_SYSTEM" = x"yes" ]; 
then
+    exit 1
+fi
+
 [ -z "$PULSE_SERVER" ]
 
 @PA_BINARY@ --start "$@"
++++++ pulseaudio-bnc881524-rtp.patch ++++++
commit 26b9d22dd24c17eb118d0205bf7b02b75d435e3c
Author: Alexander E. Patrakov <patra...@gmail.com>
Date:   Thu Jun 5 22:29:25 2014 +0600

    rtp-recv: fix crash on empty UDP packets (CVE-2014-3970)
    
    On FIONREAD returning 0 bytes, we cannot return success, as the caller
    (rtpoll_work_cb in module-rtp-recv.c) would then try to
    pa_memblock_unref(chunk.memblock) and, because memblock is NULL, trigger
    an assertion.
    
    Also we have to read out the possible empty packet from the socket, so
    that the kernel doesn't tell us again and again about it.
    
    Signed-off-by: Alexander E. Patrakov <patra...@gmail.com>

diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c
index 570737e..7b75e0e 100644
--- a/src/modules/rtp/rtp.c
+++ b/src/modules/rtp/rtp.c
@@ -182,8 +182,29 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, 
pa_mempool *pool, struct
         goto fail;
     }
 
-    if (size <= 0)
-        return 0;
+    if (size <= 0) {
+        /* size can be 0 due to any of the following reasons:
+         *
+         * 1. Somebody sent us a perfectly valid zero-length UDP packet.
+         * 2. Somebody sent us a UDP packet with a bad CRC.
+         *
+         * It is unknown whether size can actually be less than zero.
+         *
+         * In the first case, the packet has to be read out, otherwise the
+         * kernel will tell us again and again about it, thus preventing
+         * reception of any further packets. So let's just read it out
+         * now and discard it later, when comparing the number of bytes
+         * received (0) with the number of bytes wanted (1, see below).
+         *
+         * In the second case, recvmsg() will fail, thus allowing us to
+         * return the error.
+         *
+         * Just to avoid passing zero-sized memchunks and NULL pointers to
+         * recvmsg(), let's force allocation of at least one byte by setting
+         * size to 1.
+         */
+        size = 1;
+    }
 
     if (c->memchunk.length < (unsigned) size) {
         size_t l;
++++++ pulseaudio-server.fw ++++++
## Name: PulseAudio server (TCP)
## Description: Ports for PulseAudio network access (for 
module-native-protocol-tcp)
TCP="4713"
++++++ pulseaudio-wrong-memset.patch ++++++
--- src/modules/echo-cancel/adrian-aec.c.orig   2012-05-20 09:24:20.836607707 
+0200
+++ src/modules/echo-cancel/adrian-aec.c        2012-05-20 09:26:07.641603903 
+0200
@@ -167,7 +167,7 @@
     } else if (1 == a->hangover) {
       --(a->hangover);
       // My Leaky NLMS is to erase vector w when hangover expires
-      memset(a->w_arr, 0, sizeof(a->w_arr));
+      memset(a->w_arr, 0, sizeof(REAL));
     }
   }
 }
++++++ pulseaudio.service ++++++
[Unit]
Description=System wide PulseAudio instance
After=syslog.target network.target alsasound.service

[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/pulseaudio --system --log-target=journal

[Install]
WantedBy=multi-user.target
++++++ setup-pulseaudio ++++++
#!/bin/sh

LIST_OF_OSS_APPS="aumix sox"

show_help() {
    echo "setup-pulseaudio [ --enable | --disable | --auto | --status ]"
    echo ""
    echo "Modifies configuration files of some applications for PulseAudio"
    echo "  --enable   Enables PulseAudio"
    echo "  --disable  Disables PulseAudio"
    echo "  --auto     Automatically enables/disables PulseAudio based on 
configuration"
    echo "  --status   Shows activation state (disabled or enabled) for 
PulseAudio"
    echo ""
    echo "You need to be root for this command to succeed"
    echo "You may need to re-login for changes to take effect"
    exit 1
}

check_root() {
    id=`id -u`
    if [ "x$id" = "x0" ]; then
        true
    else
        echo "You need to be root in order to enable/disable pulseaudio"
        false
    fi
}

PROFNAME=/etc/profile.d/pulseaudio.sh
CPROFNAME=/etc/profile.d/pulseaudio.csh

MPLAYER_CONF=/etc/mplayer/mplayer.conf

set_variable () {
    if test -f $PROFNAME &&
        grep -q "export $1"= $PROFNAME; then
        sed -i -e "s|export $1=.*|export $1=$2|g" $PROFNAME
    else
        echo "export $1=$2" >> $PROFNAME
    fi
    if test -f $CPROFNAME &&
        grep -q "setenv $1 " $CPROFNAME; then
        sed -i -e "s|setenv $1 .*|setenv $1 $2|g" $CPROFNAME
    else
        echo "setenv $1 $2" >> $CPROFNAME
    fi
}

delete_variable () {
    if test -f $PROFNAME &&
        grep -q "export $1"= $PROFNAME; then
        sed -i -e "/export $1=.*/d" $PROFNAME
    fi
    if test -f $CPROFNAME &&
        grep -q "setenv $1 " $CPROFNAME; then
        sed -i -e "/setenv $1 .*/d" $CPROFNAME
    fi
}

setup_gconf_vendor() {
    if [ -x /usr/bin/gconftool-2 ]; then
        /usr/bin/gconftool-2 --direct --config-source \
            xml:readwrite:/etc/gconf/gconf.xml.vendor \
            "$@"
    fi
}

enable_phonon() {
    echo "Enabling PulseAudio for Phonon..."
    delete_variable PHONON_PULSEAUDIO_DISABLE
}

enable_kmix() {
    echo "Enabling PulseAudio for Kmix..."
    delete_variable KMIX_PULSEAUDIO_DISABLE
}

enable_alsa() {
    echo "Enabling PulseAudio for ALSA..."
    if [ -f /etc/alsa-pulse.conf ]; then
        set_variable ALSA_CONFIG_PATH /etc/alsa-pulse.conf
    else
        echo "Missing /etc/alsa-pluse.conf; please install alsa-plugins-pulse 
package"
        delete_variable ALSA_CONFIG_PATH
    fi
}

enable_libao() {
    echo "Enabling PulseAudio for libao..."
    if test -f /etc/libao.conf; then
        if grep -q "default_driver=pulse" /etc/libao.conf; then
            echo "Default driver is pulse already in /etc/libao.conf"
        else
            echo "default_driver=pulse" >> /etc/libao.conf
        fi
    else
        echo "default_driver=pulse" >> /etc/libao.conf
    fi
}

enable_mplayer() {
    echo "Enabling PulseAudio for mplayer..."
    if test -f $MPLAYER_CONF; then
        if grep -q '^ao *= *pulse' $MPLAYER_CONF; then
            :
        elif grep -q '^ao *=' $MPLAYER_CONF; then
            sed -i -e 's/^ao *= *\(.*\)$/ao=pulse,\1/g' $MPLAYER_CONF
        else
            echo "ao=pulse" >> $MPLAYER_CONF
        fi
    fi

    # FIXME: mplayerplug-in uses $HOME/.mplayer/mplayerplug-in.conf
}

enable_speechd() {
    echo "Enabling PulseAudio for speech dispatcher..."
    if test -f /etc/speech-dispatcher/speechd.conf; then
        if grep -q 'AudioOutputMethod' /etc/speech-dispatcher/speechd.conf; then
            sed -i -e "s|^.*AudioOutputMethod .*|AudioOutputMethod \"pulse\"|g" 
/etc/speech-dispatcher/speechd.conf
        else
            echo "AudioOutputMethod \"pulse\"" >> 
/etc/speech-dispatcher/speechd.conf
        fi
    fi
}

enable_openal() {
    # nothing to do here. openal-soft is patched to prefer pulse but
    # it won't autostart the daemon.
    return 0
}

enable_oss() {
    echo "Enabling PulseAudio for OSS..."
    for app in $LIST_OF_OSS_APPS; do
        if grep -q "alias $app='padsp $app'" $PROFNAME; then
            echo "Application $app already setup for PulseAudio"
        else
            echo "alias $app='padsp $app'" >> $PROFNAME
        fi
    done
}

enable_sdl() {
    echo "Enabling PulseAudio for SDL..."
    # For SDL, we just add an environment variable, so that apps use the PA 
audio driver
    set_variable SDL_AUDIODRIVER pulse
}

enable_timidity() {
    echo "Enabling PulseAudio for Timidity..."
    # Use esound output for timidity
    if grep -q "alias timidity='timidity -Oe'" $PROFNAME; then
        echo "Timidity already setup for using PulseAudio"
    else
        echo "alias timidity='timidity -Oe'" >> $PROFNAME
    fi
}

enable_xine() {
    #echo "Enabling PulseAudio for Xine..."
    # FIXME: xine uses $HOME/.xine/config
    return 0
}

enable_festival() {
    test -f /etc/festival.scm || return 0
    echo "Enabling PulseAudio for Festival..."
    cat << EOF >> /etc/festival.scm
;;;; Use pulseaudio to output sound
(Parameter.set 'Audio_Command "paplay -n festival \$FILE")
(Parameter.set 'Audio_Method 'Audio_Command)
(Parameter.set 'Audio_Required_Format 'snd)
EOF
}

enable_sox() {
    echo "Enabling PulseAudio for SoX..."
    set_variable AUDIODRIVER pulseaudio
}

enable_gstreamer() {
    # set autoaudiosink/src, which should pick up PA
    echo "Setting auto sink/src for gstreamer"
    setup_gconf_vendor -s -t str \
        /system/gstreamer/0.10/default/audiosink autoaudiosink
    setup_gconf_vendor -s -t str \
        /system/gstreamer/0.10/default/musicaudiosink autoaudiosink
    setup_gconf_vendor -s -t str \
        /system/gstreamer/0.10/default/chataudiosink autoaudiosink
    setup_gconf_vendor -s -t str \
        /system/gstreamer/0.10/default/audiosrc autoaudiosrc
}

enable_qemu () {
    echo "Enabling PulseAudio for QEMU/KVM"
    set_variable QEMU_AUDIO_DRV pa
}

enable_autospawn() {
    echo "Enabling PulseAudio autospawn..."
    if grep -q ^autospawn /etc/pulse/client.conf; then
        sed -i -e "s|^autospawn.*|autospawn = yes|g" /etc/pulse/client.conf
    else
        echo "autospawn = yes" >> /etc/pulse/client.conf
    fi
}

disable_alsa() {
    echo "Disabling PulseAudio for ALSA..."
    delete_variable ALSA_CONFIG_PATH
}

disable_phonon() {
    echo "Disabling PulseAudio for Phonon..."
    set_variable PHONON_PULSEAUDIO_DISABLE 1
}

disable_kmix() {
    echo "Disabling PulseAudio for Kmix..."
    set_variable KMIX_PULSEAUDIO_DISABLE 1
}

disable_libao() {
    if test -f /etc/libao.conf; then
        echo "Disabling PulseAudio for libao..."
        sed -i -e "/default_driver=pulse/d" /etc/libao.conf
    fi
}

disable_mplayer() {
    if test -f $MPLAYER_CONF; then
        echo "Disabling PulseAudio for mplayer..."
        sed -i -e 's/^ao *= *pulse,*/ao=/g' \
                -e 's/^ao *= *$/ao=alsa/g' $MPLAYER_CONF
    fi
}

disable_speechd() {
    echo "Disabling PulseAudio for speech dispatcher..."
    if test -f /etc/speech-dispatcher/speechd.conf; then
        if grep -q 'AudioOutputMethod' /etc/speech-dispatcher/speechd.conf; then
            sed -i -e "s|^.*AudioOutputMethod .*|#AudioOutputMethod 
\"pulse\"|g" /etc/speech-dispatcher/speechd.conf
        fi
    fi
}

disable_openal() {
    # nothing to do here. openal-soft is patched to prefer pulse but
    # it won't autostart the daemon.
    return 0
}

disable_oss() {
    for app in $LIST_OF_OSS_APPS; do
        sed -i -e "/alias $app='padsp $app'/d" $PROFNAME
    done
}

disable_sdl() {
    echo "Disabling PulseAudio for SDL..."
    delete_variable SDL_AUDIODRIVER
}

disable_timidity() {
    echo "Disabling PulseAudio for Timidity..."
    sed -i -e "/alias timidity='timidity -Oe'/d" $PROFNAME
}

disable_xine() {
    #echo "Disabling PulseAudio for Xine..."
    # FIXME: xine uses $HOME/.xine/config
    return 0
}

disable_festival() {
    test -f /etc/festival.scm || return 0
    echo "Disabling PulseAudio for Festival..."
    /usr/bin/sed --in-place /";;;; Use pulseaudio to output sound"/d 
/etc/festival.scm
    /usr/bin/sed --in-place /"(Parameter.set 'Audio_Command \"paplay -n 
festival \$FILE\")"/d /etc/festival.scm
    /usr/bin/sed --in-place /"(Parameter.set 'Audio_Method 'Audio_Command)"/d 
/etc/festival.scm
    /usr/bin/sed --in-place /"(Parameter.set 'Audio_Required_Format 'snd)"/d 
/etc/festival.scm
}

disable_sox() {
    echo "Disabling PulseAudio for SoX..."
    set_variable AUDIODRIVER alsa
}

disable_gstreamer() {
    echo "Setting alsasink/src for gstreamer"
    setup_gconf_vendor -s -t str \
        /system/gstreamer/0.10/default/audiosink alsasink
    setup_gconf_vendor -s -t str \
        /system/gstreamer/0.10/default/musicaudiosink alsasink
    setup_gconf_vendor -s -t str \
        /system/gstreamer/0.10/default/chataudiosink alsasink
    setup_gconf_vendor -s -t str \
        /system/gstreamer/0.10/default/audiosrc alsasrc
}

disable_qemu () {
    echo "Clearing QEMU/KVM audio setup"
    delete_variable QEMU_AUDIO_DRV
}

disable_autospawn() {
    echo "Disabling PulseAudio autospawn..."
    if grep -q ^autospawn /etc/pulse/client.conf; then
        sed -i -e "s|^autospawn.*|autospawn = no|g" /etc/pulse/client.conf
    else
        echo "autospawn = no" >> /etc/pulse/client.conf
    fi
    # kill leftover PA processes
    killall pulseaudio > /dev/null 2>&1
}

enable_all() {
    enable_alsa
    enable_libao
    enable_mplayer
    enable_openal
    enable_oss
    enable_sdl
    enable_timidity
    enable_xine
    enable_festival
    enable_phonon
    enable_kmix
    enable_speechd
    enable_sox
    enable_gstreamer
    enable_qemu
    enable_autospawn
}

disable_all() {
    disable_alsa
    disable_libao
    disable_mplayer
    disable_openal
    disable_oss
    disable_sdl
    disable_timidity
    disable_xine
    disable_festival
    disable_phonon
    disable_kmix
    disable_speechd
    disable_sox
    disable_gstreamer
    disable_qemu
    disable_autospawn
}

case $1 in
    --enable)
        check_root || exit 1
        ENABLE=1
        enable_all
        ;;
    --disable)
        check_root || exit 1
        ENABLE=0
        disable_all
        ;;
    --auto)
        check_root || exit 1
        if [ -f /etc/sysconfig/sound ]; then
            . /etc/sysconfig/sound
        fi
        if [ "x$PULSEAUDIO_ENABLE" = "xyes" ]; then
            enable_all
        elif [ "x$PULSEAUDIO_ENABLE" = "xcustom" ]; then
            echo "Custom configuration detected, doing nothing."
        else
            disable_all
        fi
        exit 0
        ;;
    --status)
        if [ -f /etc/sysconfig/sound ]; then
            . /etc/sysconfig/sound
        fi
        if [ "x$PULSEAUDIO_ENABLE" = "xyes" ]; then
            echo "enabled"
        elif [ "x$PULSEAUDIO_ENABLE" = "xcustom" ]; then
            echo "custom configured"
        else
            echo "disabled"
        fi
        exit 0
        ;;
    *)
        show_help
        ;;
esac

# Now, update /etc/sysconfig/sound with the PA status
if grep -q PULSEAUDIO_ENABLE /etc/sysconfig/sound; then
    if [  "x$ENABLE" = "x1" ]; then
        sed -i -e "s|PULSEAUDIO_ENABLE=\"no\"|PULSEAUDIO_ENABLE=\"yes\"|g" 
/etc/sysconfig/sound
    else
        sed -i -e "s|PULSEAUDIO_ENABLE=\"yes\"|PULSEAUDIO_ENABLE=\"no\"|g" 
/etc/sysconfig/sound
    fi
else
    if [ "x$ENABLE" = "x1" ]; then
        echo "PULSEAUDIO_ENABLE=\"yes\"" >> /etc/sysconfig/sound
    else
        echo "PULSEAUDIO_ENABLE=\"no\"" >> /etc/sysconfig/sound
    fi
fi
exit 0
++++++ suppress-socket-error-msg.diff ++++++
---
 src/pulsecore/socket-client.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: pulseaudio-0.99.2/src/pulsecore/socket-client.c
===================================================================
--- pulseaudio-0.99.2.orig/src/pulsecore/socket-client.c
+++ pulseaudio-0.99.2/src/pulsecore/socket-client.c
@@ -253,7 +253,7 @@ static int sockaddr_prepare(pa_socket_cl
     c->local = pa_socket_address_is_local(sa);
 
     if ((c->fd = pa_socket_cloexec(sa->sa_family, SOCK_STREAM, 0)) < 0) {
-        pa_log("socket(): %s", pa_cstrerror(errno));
+        /*pa_log("socket(): %s", pa_cstrerror(errno));*/
         return -1;
     }
 
++++++ sysconfig.sound-pulseaudio ++++++

## Path:        Hardware/Soundcard/PulseAudio
## Description: PulseAudio configuration
## Type:        list(yes,no,custom)
#
# Enable or disable PulseAudio system. Can be set to "custom" to not have
# scripts automatically change sound-related configuration for PulseAudio.
#
PULSEAUDIO_ENABLE="yes"

## Path:        Hardware/Soundcard/PulseAudio/SystemWide
## Description: System Wide PulseAudio
## Type:        list(yes,no)
#
# Allows you to configure that you have system wide PulseAudio daemon. Such is
# setup is not recommended. To make it work, you would need
# pulseaudio-systemwide package and enable pulseaudio systemd service. If you
# are not sure whether you want this, you don't. So unless you know what you
# are doing, keep this set to "no".
#
PULSEAUDIO_SYSTEM="no"

Reply via email to