[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.11-108-g916899a

Lennart Poettering gitmailer-noreply at 0pointer.de
Wed Aug 13 04:59:56 PDT 2008


This is an automated email from the git hooks/post-receive script. It was
generated because of a push to the "PulseAudio Sound Server" repository.

The master branch has been updated
      from  7c5a95950e05fd8889c162b9e55d07d07958fd77 (commit)

- Log -----------------------------------------------------------------
916899a... pass force_refresh=FALSE to all volume/mute read invocations
abd85af... drop 0db reset functions since they are not necessary anymore
8a10eba... extend hardware dB scale in software to full range if necessary, instead of reverting back to software-only volume control
3ec4a5d... rework volume/mute APIs: split out pa_xx_set_soft_volume() and add force_refresh argument to read functions
29daef7... add new function pa_alsa_volume_divide()
8ab85fd... reword some log messages
e4adcf7... add new API function pa_cvolume_max()
a176f68... reset lock_fd_mutex after destruction
3c88af7... fix protocol destruction
-----------------------------------------------------------------------

Summary of changes:
 src/modules/alsa-util.c             |   80 ++++--------
 src/modules/alsa-util.h             |    6 +-
 src/modules/module-alsa-sink.c      |  247 +++++++++++++++++++++--------------
 src/modules/module-alsa-source.c    |  239 +++++++++++++++++++++-------------
 src/modules/module-device-restore.c |    8 +-
 src/modules/module-lirc.c           |    4 +-
 src/modules/module-mmkbd-evdev.c    |    4 +-
 src/modules/module-protocol-stub.c  |    7 +-
 src/pulse/lock-autospawn.c          |    1 +
 src/pulse/volume.c                  |   12 ++
 src/pulse/volume.h                  |    3 +
 src/pulsecore/cli-command.c         |    8 +-
 src/pulsecore/cli-text.c            |    8 +-
 src/pulsecore/protocol-native.c     |    8 +-
 src/pulsecore/sink.c                |   21 +++-
 src/pulsecore/sink.h                |    5 +-
 src/pulsecore/source.c              |   21 +++-
 src/pulsecore/source.h              |    5 +-
 18 files changed, 402 insertions(+), 285 deletions(-)

-----------------------------------------------------------------------

commit 3c88af711eee69d6bfda4268e0492278bcb59a02
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 13 13:51:13 2008 +0200

    fix protocol destruction

diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c
index 8136c6f..4fe439f 100644
--- a/src/modules/module-protocol-stub.c
+++ b/src/modules/module-protocol-stub.c
@@ -260,7 +260,7 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
-    u = pa_xnew0(struct userdata, 1);
+    m->userdata = u = pa_xnew0(struct userdata, 1);
     u->module = m;
 
 #if defined(USE_PROTOCOL_SIMPLE)
@@ -368,8 +368,6 @@ int pa__init(pa_module*m) {
 #  endif
 #endif
 
-    m->userdata = u;
-
     if (ma)
         pa_modargs_free(ma);
 
@@ -390,7 +388,8 @@ void pa__done(pa_module*m) {
 
     pa_assert(m);
 
-    u = m->userdata;
+    if (!(u = m->userdata))
+        return;
 
 #if defined(USE_PROTOCOL_SIMPLE)
     if (u->simple_protocol) {

commit a176f68e0abb32331223dbb0dfa2dfcbe8af1cd6
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 13 13:51:43 2008 +0200

    reset lock_fd_mutex after destruction

diff --git a/src/pulse/lock-autospawn.c b/src/pulse/lock-autospawn.c
index 33a5311..d36b669 100644
--- a/src/pulse/lock-autospawn.c
+++ b/src/pulse/lock-autospawn.c
@@ -134,6 +134,7 @@ static void unref(pa_bool_t after_fork) {
     pa_mutex_unlock(lock_fd_mutex);
 
     pa_mutex_free(lock_fd_mutex);
+    lock_fd_mutex = NULL;
 
     pa_close(pipe_fd[0]);
     pa_close(pipe_fd[1]);

commit e4adcf7071a34d6338c564db11d8bc97a7b3c264
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 13 13:52:20 2008 +0200

    add new API function pa_cvolume_max()

diff --git a/src/pulse/volume.c b/src/pulse/volume.c
index 625eb19..f0d4527 100644
--- a/src/pulse/volume.c
+++ b/src/pulse/volume.c
@@ -74,6 +74,18 @@ pa_volume_t pa_cvolume_avg(const pa_cvolume *a) {
     return (pa_volume_t) sum;
 }
 
+pa_volume_t pa_cvolume_max(const pa_cvolume *a) {
+    pa_volume_t m = 0;
+    int i;
+    pa_assert(a);
+
+    for (i = 0; i < a->channels; i++)
+        if (a->values[i] > m)
+            m = a->values[i];
+
+    return m;
+}
+
 pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) {
     return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a)* pa_sw_volume_to_linear(b));
 }
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index 4fdbf65..a356f74 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -134,6 +134,9 @@ char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c);
 /** Return the average volume of all channels */
 pa_volume_t pa_cvolume_avg(const pa_cvolume *a) PA_GCC_PURE;
 
+/** Return the maximum volume of all channels. \since 0.9.12 */
+pa_volume_t pa_cvolume_max(const pa_cvolume *a) PA_GCC_PURE;
+
 /** Return TRUE when the passed cvolume structure is valid, FALSE otherwise */
 int pa_cvolume_valid(const pa_cvolume *v) PA_GCC_PURE;
 

commit 8ab85fdf9e8d5465ae29434f6618b63c3511b767
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 13 13:53:31 2008 +0200

    reword some log messages

diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c
index c987315..2dcf6d9 100644
--- a/src/modules/alsa-util.c
+++ b/src/modules/alsa-util.c
@@ -808,7 +808,7 @@ int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel
     if (channel_map->channels > 1 &&
         ((playback && snd_mixer_selem_has_playback_volume_joined(elem)) ||
          (!playback && snd_mixer_selem_has_capture_volume_joined(elem)))) {
-        pa_log_info("ALSA device lacks independant volume controls for each channel, falling back to software volume control.");
+        pa_log_info("ALSA device lacks independant volume controls for each channel.");
         return -1;
     }
 
@@ -820,7 +820,7 @@ int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel
         id = alsa_channel_ids[channel_map->map[i]];
 
         if (!is_mono && id == SND_MIXER_SCHN_UNKNOWN) {
-            pa_log_info("Configured channel map contains channel '%s' that is unknown to the ALSA mixer. Falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i]));
+            pa_log_info("Configured channel map contains channel '%s' that is unknown to the ALSA mixer.", pa_channel_position_to_string(channel_map->map[i]));
             return -1;
         }
 
@@ -832,7 +832,7 @@ int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel
         if ((playback && (!snd_mixer_selem_has_playback_channel(elem, id) || (is_mono && !snd_mixer_selem_is_playback_mono(elem)))) ||
             (!playback && (!snd_mixer_selem_has_capture_channel(elem, id) || (is_mono && !snd_mixer_selem_is_capture_mono(elem))))) {
 
-            pa_log_info("ALSA device lacks separate volumes control for channel '%s', falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i]));
+            pa_log_info("ALSA device lacks separate volumes control for channel '%s'", pa_channel_position_to_string(channel_map->map[i]));
             return -1;
         }
 

commit 29daef7a265db1977db4eb2eb68dd85c943fceef
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 13 13:54:17 2008 +0200

    add new function pa_alsa_volume_divide()

diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c
index 2dcf6d9..be3cdf4 100644
--- a/src/modules/alsa-util.c
+++ b/src/modules/alsa-util.c
@@ -1117,3 +1117,27 @@ pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) {
 
     return item;
 }
+
+pa_cvolume *pa_alsa_volume_divide(pa_cvolume *r, const pa_cvolume *t) {
+    unsigned i;
+
+    pa_assert(r);
+    pa_assert(t);
+    pa_assert(r->channels == t->channels);
+
+    for (i = 0; i < r->channels; i++) {
+        double a, b, c;
+
+        a = pa_sw_volume_to_linear(r->values[i]); /* the hw volume */
+        b = pa_sw_volume_to_linear(t->values[i]); /* the intended volume */
+
+        if (a <= 0)
+            c = 0;
+        else
+            c = b / a;
+
+        r->values[i] = pa_sw_volume_from_linear(c);
+    }
+
+    return r;
+}
diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h
index 4de8bcd..1b73200 100644
--- a/src/modules/alsa-util.h
+++ b/src/modules/alsa-util.h
@@ -26,6 +26,7 @@
 #include <asoundlib.h>
 
 #include <pulse/sample.h>
+#include <pulse/volume.h>
 #include <pulse/mainloop-api.h>
 #include <pulse/channelmap.h>
 #include <pulse/proplist.h>
@@ -94,4 +95,6 @@ int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents);
 
 pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll);
 
+pa_cvolume *pa_alsa_volume_divide(pa_cvolume *r, const pa_cvolume *t);
+
 #endif

commit 3ec4a5db992151b1bbc8b6fb8ccd4eca523adc2b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 13 13:55:58 2008 +0200

    rework volume/mute APIs: split out pa_xx_set_soft_volume() and add force_refresh argument to read functions

diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 4102f31..24fb891 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -856,18 +856,29 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) {
         s->set_volume = NULL;
 
     if (!s->set_volume)
-        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, volume, 0, NULL);
+        pa_sink_set_soft_volume(s, volume);
 
     if (changed)
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
 /* Called from main thread */
-const pa_cvolume *pa_sink_get_volume(pa_sink *s) {
+void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
+    pa_sink_assert_ref(s);
+    pa_assert(volume);
+
+    if (PA_SINK_IS_LINKED(s->state))
+        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, volume, 0, NULL);
+    else
+        s->thread_info.soft_volume = *volume;
+}
+
+/* Called from main thread */
+const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
     pa_sink_assert_ref(s);
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
-    if (s->refresh_volume) {
+    if (s->refresh_volume || force_refresh) {
         struct pa_cvolume old_volume = s->volume;
 
         if (s->get_volume && s->get_volume(s) < 0)
@@ -904,12 +915,12 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
 }
 
 /* Called from main thread */
-pa_bool_t pa_sink_get_mute(pa_sink *s) {
+pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
 
     pa_sink_assert_ref(s);
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
-    if (s->refresh_muted) {
+    if (s->refresh_muted || force_refresh) {
         pa_bool_t old_muted = s->muted;
 
         if (s->get_mute && s->get_mute(s) < 0)
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 604be26..0aed8bc 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -239,9 +239,10 @@ int pa_sink_suspend(pa_sink *s, pa_bool_t suspend);
 int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend);
 
 void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume);
-const pa_cvolume *pa_sink_get_volume(pa_sink *sink);
+void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume);
+const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh);
 void pa_sink_set_mute(pa_sink *sink, pa_bool_t mute);
-pa_bool_t pa_sink_get_mute(pa_sink *sink);
+pa_bool_t pa_sink_get_mute(pa_sink *sink, pa_bool_t force_refres);
 
 unsigned pa_sink_linked_by(pa_sink *s); /* Number of connected streams */
 unsigned pa_sink_used_by(pa_sink *s); /* Number of connected streams which are not corked */
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 3162069..7ed32e9 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -520,18 +520,29 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
         s->set_volume = NULL;
 
     if (!s->set_volume)
-        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, volume, 0, NULL);
+        pa_source_set_soft_volume(s, volume);
 
     if (changed)
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
 /* Called from main thread */
-const pa_cvolume *pa_source_get_volume(pa_source *s) {
+void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
+    pa_source_assert_ref(s);
+    pa_assert(volume);
+
+    if (PA_SOURCE_IS_LINKED(s->state))
+        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, volume, 0, NULL);
+    else
+        s->thread_info.soft_volume = *volume;
+}
+
+/* Called from main thread */
+const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
     pa_source_assert_ref(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
-    if (s->refresh_volume) {
+    if (s->refresh_volume || force_refresh) {
         pa_cvolume old_volume = s->volume;
 
         if (s->get_volume && s->get_volume(s) < 0)
@@ -568,12 +579,12 @@ void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
 }
 
 /* Called from main thread */
-pa_bool_t pa_source_get_mute(pa_source *s) {
+pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
 
     pa_source_assert_ref(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
-    if (s->refresh_muted) {
+    if (s->refresh_muted || force_refresh) {
         pa_bool_t old_muted = s->muted;
 
         if (s->get_mute && s->get_mute(s) < 0)
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index f4a17e8..706ff1b 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -226,9 +226,10 @@ int pa_source_suspend(pa_source *s, pa_bool_t suspend);
 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend);
 
 void pa_source_set_volume(pa_source *source, const pa_cvolume *volume);
-const pa_cvolume *pa_source_get_volume(pa_source *source);
+void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume);
+const pa_cvolume *pa_source_get_volume(pa_source *source, pa_bool_t force_refresh);
 void pa_source_set_mute(pa_source *source, pa_bool_t mute);
-pa_bool_t pa_source_get_mute(pa_source *source);
+pa_bool_t pa_source_get_mute(pa_source *source, pa_bool_t force_refresh);
 
 unsigned pa_source_linked_by(pa_source *s); /* Number of connected streams */
 unsigned pa_source_used_by(pa_source *s); /* Number of connected streams that are not corked */

commit 8a10eba744c42cb5db4e6446c2f77b6cbc5eb028
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 13 13:59:06 2008 +0200

    extend hardware dB scale in software to full range if necessary, instead of reverting back to software-only volume control

diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c
index cba959f..255896c 100644
--- a/src/modules/module-alsa-sink.c
+++ b/src/modules/module-alsa-sink.c
@@ -68,8 +68,7 @@ PA_MODULE_USAGE(
         "mmap=<enable memory mapping?> "
         "tsched=<enable system timer based scheduling mode?> "
         "tsched_buffer_size=<buffer size when using timer based scheduling> "
-        "tsched_buffer_watermark=<lower fill watermark> "
-        "mixer_reset=<reset hw volume and mute settings to sane defaults when falling back to software?>");
+        "tsched_buffer_watermark=<lower fill watermark>");
 
 static const char* const valid_modargs[] = {
     "sink_name",
@@ -85,7 +84,6 @@ static const char* const valid_modargs[] = {
     "tsched",
     "tsched_buffer_size",
     "tsched_buffer_watermark",
-    "mixer_reset",
     NULL
 };
 
@@ -112,6 +110,8 @@ struct userdata {
     long hw_volume_max, hw_volume_min;
     long hw_dB_max, hw_dB_min;
     pa_bool_t hw_dB_supported;
+    pa_bool_t mixer_seperate_channels;
+    pa_cvolume hardware_volume;
 
     size_t frame_size, fragment_size, hwbuf_size, tsched_watermark;
     unsigned nfragments;
@@ -737,8 +737,8 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
         return 0;
 
     if (mask & SND_CTL_EVENT_MASK_VALUE) {
-        pa_sink_get_volume(u->sink);
-        pa_sink_get_mute(u->sink);
+        pa_sink_get_volume(u->sink, TRUE);
+        pa_sink_get_mute(u->sink, TRUE);
     }
 
     return 0;
@@ -747,30 +747,60 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
 static int sink_get_volume_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     int err;
-    int i;
+    unsigned i;
+    pa_cvolume r;
+    char t[PA_CVOLUME_SNPRINT_MAX];
 
     pa_assert(u);
     pa_assert(u->mixer_elem);
 
-    for (i = 0; i < s->sample_spec.channels; i++) {
-        long alsa_vol;
+    if (u->mixer_seperate_channels) {
 
-        pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, u->mixer_map[i]));
+        r.channels = s->sample_spec.channels;
 
-        if (u->hw_dB_supported) {
+        for (i = 0; i < s->sample_spec.channels; i++) {
+            long alsa_vol;
 
-            if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) >= 0) {
-                s->volume.values[i] = pa_sw_volume_from_dB(alsa_vol / 100.0);
-                continue;
-            }
+            if (u->hw_dB_supported) {
+
+                if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+                    goto fail;
+
+                r.values[i] = pa_sw_volume_from_dB((double) alsa_vol / 100.0);
+            } else {
 
-            u->hw_dB_supported = FALSE;
+                if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+                    goto fail;
+
+                r.values[i] = (pa_volume_t) round(((double) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+            }
         }
 
-        if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+    } else {
+        long alsa_vol;
+
+        pa_assert(u->hw_dB_supported);
+
+        if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, SND_MIXER_SCHN_MONO, &alsa_vol)) < 0)
             goto fail;
 
-        s->volume.values[i] = (pa_volume_t) roundf(((float) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+        pa_cvolume_set(&r, s->sample_spec.channels, pa_sw_volume_from_dB((double) alsa_vol / 100.0));
+    }
+
+    pa_log_debug("Read hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &r));
+
+    if (!pa_cvolume_equal(&u->hardware_volume, &r)) {
+
+        u->hardware_volume = s->volume = r;
+
+        if (u->hw_dB_supported) {
+            pa_cvolume reset;
+
+            /* Hmm, so the hardware volume changed, let's reset our software volume */
+
+            pa_cvolume_reset(&reset, s->sample_spec.channels);
+            pa_sink_set_soft_volume(s, &reset);
+        }
     }
 
     return 0;
@@ -784,45 +814,90 @@ fail:
 static int sink_set_volume_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     int err;
-    int i;
+    unsigned i;
+    pa_cvolume r;
 
     pa_assert(u);
     pa_assert(u->mixer_elem);
 
-    for (i = 0; i < s->sample_spec.channels; i++) {
-        long alsa_vol;
-        pa_volume_t vol;
+    if (u->mixer_seperate_channels) {
 
-        pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, u->mixer_map[i]));
+        r.channels = s->sample_spec.channels;
 
-        vol = PA_MIN(s->volume.values[i], PA_VOLUME_NORM);
+        for (i = 0; i < s->sample_spec.channels; i++) {
+            long alsa_vol;
+            pa_volume_t vol;
 
-        if (u->hw_dB_supported) {
-            alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
-            alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
+            vol = s->volume.values[i];
 
-            if ((err = snd_mixer_selem_set_playback_dB(u->mixer_elem, u->mixer_map[i], alsa_vol, -1)) >= 0) {
+            if (u->hw_dB_supported) {
 
-                if (snd_mixer_selem_get_playback_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol) >= 0)
-                    s->volume.values[i] = pa_sw_volume_from_dB(alsa_vol / 100.0);
+                alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
+                alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
 
-                continue;
-            }
+                if ((err = snd_mixer_selem_set_playback_dB(u->mixer_elem, u->mixer_map[i], alsa_vol, 1)) < 0)
+                    goto fail;
 
-            u->hw_dB_supported = FALSE;
+                if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+                    goto fail;
 
+                r.values[i] = pa_sw_volume_from_dB((double) alsa_vol / 100.0);
+            } else {
+
+                alsa_vol = (long) round(((double) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
+                alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
+
+                if ((err = snd_mixer_selem_set_playback_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0)
+                    goto fail;
+
+                if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+                    goto fail;
+
+                r.values[i] = (pa_volume_t) round(((double) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+            }
         }
 
-        alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
-        alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
+    } else {
+        pa_volume_t vol;
+        long alsa_vol;
+
+        pa_assert(u->hw_dB_supported);
+
+        vol = pa_cvolume_max(&s->volume);
+
+        alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
+        alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
+
+        if ((err = snd_mixer_selem_set_playback_dB_all(u->mixer_elem, alsa_vol, 1)) < 0)
+            goto fail;
 
-        if ((err = snd_mixer_selem_set_playback_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0)
+        if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, SND_MIXER_SCHN_MONO, &alsa_vol)) < 0)
             goto fail;
 
-        if (snd_mixer_selem_get_playback_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol) >= 0)
-            s->volume.values[i] = (pa_volume_t) roundf(((float) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+        pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) alsa_vol / 100.0));
     }
 
+    u->hardware_volume = r;
+
+    if (u->hw_dB_supported) {
+        char t[PA_CVOLUME_SNPRINT_MAX];
+
+        /* Match exactly what the user requested by software */
+
+        pa_alsa_volume_divide(&r, &s->volume);
+        pa_sink_set_soft_volume(s, &r);
+
+        pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->volume));
+        pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &u->hardware_volume));
+        pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint(t, sizeof(t), &r));
+
+    } else
+
+        /* We can't match exactly what the user requested, hence let's
+         * at least tell the user about it */
+
+        s->volume = r;
+
     return 0;
 
 fail:
@@ -1100,7 +1175,7 @@ int pa__init(pa_module*m) {
     const char *name;
     char *name_buf = NULL;
     pa_bool_t namereg_fail;
-    pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, mixer_reset = TRUE;
+    pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d;
     pa_usec_t usec;
     pa_sink_new_data data;
 
@@ -1157,11 +1232,6 @@ int pa__init(pa_module*m) {
         use_tsched = FALSE;
     }
 
-    if (pa_modargs_get_value_boolean(ma, "mixer_reset", &mixer_reset) < 0) {
-        pa_log("Failed to parse mixer_reset argument.");
-        goto fail;
-    }
-
     u = pa_xnew0(struct userdata, 1);
     u->core = m->core;
     u->module = m;
@@ -1322,6 +1392,8 @@ int pa__init(pa_module*m) {
     u->hw_dB_supported = FALSE;
     u->hw_dB_min = u->hw_dB_max = 0;
     u->hw_volume_min = u->hw_volume_max = 0;
+    u->mixer_seperate_channels = FALSE;
+    pa_cvolume_mute(&u->hardware_volume, u->sink->sample_spec.channels);
 
     if (use_tsched)
         fix_tsched_watermark(u);
@@ -1349,76 +1421,51 @@ int pa__init(pa_module*m) {
     if (u->mixer_handle) {
         pa_assert(u->mixer_elem);
 
-        if (snd_mixer_selem_has_playback_volume(u->mixer_elem))
-
-            if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, TRUE) >= 0 &&
-                snd_mixer_selem_get_playback_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max) >= 0) {
-
-                pa_bool_t suitable = TRUE;
+        if (snd_mixer_selem_has_playback_volume(u->mixer_elem)) {
+            pa_bool_t suitable = TRUE;
 
+            if (snd_mixer_selem_get_playback_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max) < 0) {
+                pa_log_info("Failed to get volume range. Falling back to software volume control.");
+                suitable = FALSE;
+            } else {
                 pa_log_info("Volume ranges from %li to %li.", u->hw_volume_min, u->hw_volume_max);
+                pa_assert(u->hw_volume_min < u->hw_volume_max);
+            }
 
-                if (u->hw_volume_min > u->hw_volume_max) {
-
-                    pa_log_info("Minimal volume %li larger than maximum volume %li. Strange stuff Falling back to software volume control.", u->hw_volume_min, u->hw_volume_max);
-                    suitable = FALSE;
-
-                } else if (u->hw_volume_max - u->hw_volume_min < 3) {
-
-                    pa_log_info("Device has less than 4 volume levels. Falling back to software volume control.");
-                    suitable = FALSE;
-
-                } else if (snd_mixer_selem_get_playback_dB_range(u->mixer_elem, &u->hw_dB_min, &u->hw_dB_max) >= 0) {
-
-                    /* u->hw_dB_max = 0; u->hw_dB_min = -3000; Use this to make valgrind shut up */
-
-                    pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", u->hw_dB_min/100.0, u->hw_dB_max/100.0);
-
-                    /* Let's see if this thing actually is useful for muting */
-                    if (u->hw_dB_min > -6000) {
-                        pa_log_info("Device cannot attenuate for more than -60 dB (only %0.2f dB supported), falling back to software volume control.", ((double) u->hw_dB_min) / 100);
-
-                        suitable = FALSE;
-                    } else if (u->hw_dB_max < 0) {
-
-                        pa_log_info("Device is still attenuated at maximum volume setting (%0.2f dB is maximum). Strange stuff. Falling back to software volume control.", ((double) u->hw_dB_max) / 100);
-                        suitable = FALSE;
+            if (snd_mixer_selem_get_playback_dB_range(u->mixer_elem, &u->hw_dB_min, &u->hw_dB_max) < 0)
+                pa_log_info("Mixer doesn't support dB information.");
+            else {
+                pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", u->hw_dB_min/100.0, u->hw_dB_max/100.0);
+                pa_assert(u->hw_dB_min < u->hw_dB_max);
+                u->hw_dB_supported = TRUE;
+            }
 
-                    } else if (u->hw_dB_min >= u->hw_dB_max) {
+            if (suitable &&
+                !u->hw_dB_supported &&
+                u->hw_volume_max - u->hw_volume_min < 3) {
 
-                        pa_log_info("Minimal dB (%0.2f) larger or equal to maximum dB (%0.2f). Strange stuff. Falling back to software volume control.", ((double) u->hw_dB_min) / 100, ((double) u->hw_dB_max) / 100);
-                        suitable = FALSE;
+                pa_log_info("Device doesn't do dB volume and has less than 4 volume levels. Falling back to software volume control.");
+                suitable = FALSE;
+            }
 
-                    } else {
+            if (suitable) {
+                u->mixer_seperate_channels = pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, TRUE) >= 0;
 
-                        if (u->hw_dB_max > 0) {
-                            /* dB > 0 means overamplification, and clipping, we don't want that here */
-                            pa_log_info("Device can do overamplification for %0.2f dB. Limiting to 0 db", ((double) u->hw_dB_max) / 100);
-                            u->hw_dB_max = 0;
-                        }
+                u->sink->get_volume = sink_get_volume_cb;
+                u->sink->set_volume = sink_set_volume_cb;
+                u->sink->flags |= PA_SINK_HW_VOLUME_CTRL | (u->hw_dB_supported ? PA_SINK_DECIBEL_VOLUME : 0);
+                pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->hw_dB_supported ? "supported" : "not supported");
 
-                        u->hw_dB_supported = TRUE;
-                    }
-                }
-
-                if (suitable) {
-                    u->sink->get_volume = sink_get_volume_cb;
-                    u->sink->set_volume = sink_set_volume_cb;
-                    u->sink->flags |= PA_SINK_HW_VOLUME_CTRL | (u->hw_dB_supported ? PA_SINK_DECIBEL_VOLUME : 0);
-                    pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->hw_dB_supported ? "supported" : "not supported");
-
-                } else if (mixer_reset) {
-                    pa_log_info("Using software volume control. Trying to reset sound card to 0 dB.");
-                    pa_alsa_0dB_playback(u->mixer_elem);
-                } else
-                    pa_log_info("Using software volume control. Leaving hw mixer controls untouched.");
-            }
+            } else
+                pa_log_info("Using software volume control.");
+        }
 
         if (snd_mixer_selem_has_playback_switch(u->mixer_elem)) {
             u->sink->get_mute = sink_get_mute_cb;
             u->sink->set_mute = sink_set_mute_cb;
             u->sink->flags |= PA_SINK_HW_MUTE_CTRL;
-        }
+        } else
+            pa_log_info("Using software mute control.");
 
         u->mixer_fdl = pa_alsa_fdlist_new();
 
diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c
index f1b6622..0e4efad 100644
--- a/src/modules/module-alsa-source.c
+++ b/src/modules/module-alsa-source.c
@@ -69,8 +69,7 @@ PA_MODULE_USAGE(
         "mmap=<enable memory mapping?> "
         "tsched=<enable system timer based scheduling mode?> "
         "tsched_buffer_size=<buffer size when using timer based scheduling> "
-        "tsched_buffer_watermark=<upper fill watermark> "
-        "mixer_reset=<reset hw volume and mute settings to sane defaults when falling back to software?>");
+        "tsched_buffer_watermark=<upper fill watermark>");
 
 static const char* const valid_modargs[] = {
     "source_name",
@@ -86,7 +85,6 @@ static const char* const valid_modargs[] = {
     "tsched",
     "tsched_buffer_size",
     "tsched_buffer_watermark",
-    "mixer_reset",
     NULL
 };
 
@@ -113,6 +111,9 @@ struct userdata {
     long hw_volume_max, hw_volume_min;
     long hw_dB_max, hw_dB_min;
     pa_bool_t hw_dB_supported;
+    pa_bool_t mixer_seperate_channels;
+
+    pa_cvolume hardware_volume;
 
     size_t frame_size, fragment_size, hwbuf_size, tsched_watermark;
     unsigned nfragments;
@@ -680,8 +681,8 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
         return 0;
 
     if (mask & SND_CTL_EVENT_MASK_VALUE) {
-        pa_source_get_volume(u->source);
-        pa_source_get_mute(u->source);
+        pa_source_get_volume(u->source, TRUE);
+        pa_source_get_mute(u->source, TRUE);
     }
 
     return 0;
@@ -690,30 +691,60 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
 static int source_get_volume_cb(pa_source *s) {
     struct userdata *u = s->userdata;
     int err;
-    int i;
+    unsigned i;
+    pa_cvolume r;
+    char t[PA_CVOLUME_SNPRINT_MAX];
 
     pa_assert(u);
     pa_assert(u->mixer_elem);
 
-    for (i = 0; i < s->sample_spec.channels; i++) {
-        long alsa_vol;
+    if (u->mixer_seperate_channels) {
 
-        pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i]));
+        r.channels = s->sample_spec.channels;
 
-        if (u->hw_dB_supported) {
+        for (i = 0; i < s->sample_spec.channels; i++) {
+            long alsa_vol;
 
-            if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) >= 0) {
-                s->volume.values[i] = pa_sw_volume_from_dB(alsa_vol / 100.0);
-                continue;
-            }
+            if (u->hw_dB_supported) {
+
+                if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+                    goto fail;
+
+                r.values[i] = pa_sw_volume_from_dB((double) alsa_vol / 100.0);
+            } else {
+
+                if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+                    goto fail;
 
-            u->hw_dB_supported = FALSE;
+                r.values[i] = (pa_volume_t) round(((double) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+            }
         }
 
-        if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+    } else {
+        long alsa_vol;
+
+        pa_assert(u->hw_dB_supported);
+
+        if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, SND_MIXER_SCHN_MONO, &alsa_vol)) < 0)
             goto fail;
 
-        s->volume.values[i] = (pa_volume_t) roundf(((float) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+        pa_cvolume_set(&r, s->sample_spec.channels, pa_sw_volume_from_dB((double) alsa_vol / 100.0));
+    }
+
+    pa_log_debug("Read hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &r));
+
+    if (!pa_cvolume_equal(&u->hardware_volume, &r)) {
+
+        u->hardware_volume = s->volume = r;
+
+        if (u->hw_dB_supported) {
+            pa_cvolume reset;
+
+            /* Hmm, so the hardware volume changed, let's reset our software volume */
+
+            pa_cvolume_reset(&reset, s->sample_spec.channels);
+            pa_source_set_soft_volume(s, &reset);
+        }
     }
 
     return 0;
@@ -727,45 +758,90 @@ fail:
 static int source_set_volume_cb(pa_source *s) {
     struct userdata *u = s->userdata;
     int err;
-    int i;
+    unsigned i;
+    pa_cvolume r;
 
     pa_assert(u);
     pa_assert(u->mixer_elem);
 
-    for (i = 0; i < s->sample_spec.channels; i++) {
-        long alsa_vol;
-        pa_volume_t vol;
+        if (u->mixer_seperate_channels) {
 
-        pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i]));
+        r.channels = s->sample_spec.channels;
 
-        vol = PA_MIN(s->volume.values[i], PA_VOLUME_NORM);
+        for (i = 0; i < s->sample_spec.channels; i++) {
+            long alsa_vol;
+            pa_volume_t vol;
 
-        if (u->hw_dB_supported) {
-            alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
-            alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
+            vol = s->volume.values[i];
 
+            if (u->hw_dB_supported) {
 
-            if ((err = snd_mixer_selem_set_capture_dB(u->mixer_elem, u->mixer_map[i], alsa_vol, -1)) >= 0) {
+                alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
+                alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
 
-                if (snd_mixer_selem_get_capture_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol) >= 0)
-                    s->volume.values[i] = pa_sw_volume_from_dB(alsa_vol / 100.0);
+                if ((err = snd_mixer_selem_set_capture_dB(u->mixer_elem, u->mixer_map[i], alsa_vol, 1)) < 0)
+                    goto fail;
 
-                continue;
-            }
+                if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+                    goto fail;
+
+                r.values[i] = pa_sw_volume_from_dB((double) alsa_vol / 100.0);
+            } else {
 
-            u->hw_dB_supported = FALSE;
+                alsa_vol = (long) round(((double) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
+                alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
+
+                if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0)
+                    goto fail;
+
+                if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
+                    goto fail;
+
+                r.values[i] = (pa_volume_t) round(((double) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+            }
         }
 
-        alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
-        alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
+    } else {
+        pa_volume_t vol;
+        long alsa_vol;
+
+        pa_assert(u->hw_dB_supported);
+
+        vol = pa_cvolume_max(&s->volume);
 
-        if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0)
+        alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
+        alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max);
+
+        if ((err = snd_mixer_selem_set_capture_dB_all(u->mixer_elem, alsa_vol, 1)) < 0)
+            goto fail;
+
+        if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, SND_MIXER_SCHN_MONO, &alsa_vol)) < 0)
             goto fail;
 
-        if (snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol) >= 0)
-            s->volume.values[i] = (pa_volume_t) roundf(((float) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+        pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) alsa_vol / 100.0));
     }
 
+    u->hardware_volume = r;
+
+    if (u->hw_dB_supported) {
+        char t[PA_CVOLUME_SNPRINT_MAX];
+
+        /* Match exactly what the user requested by software */
+
+        pa_alsa_volume_divide(&r, &s->volume);
+        pa_source_set_soft_volume(s, &r);
+
+        pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->volume));
+        pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &u->hardware_volume));
+        pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint(t, sizeof(t), &r));
+
+    } else
+
+        /* We can't match exactly what the user requested, hence let's
+         * at least tell the user about it */
+
+        s->volume = r;
+
     return 0;
 
 fail:
@@ -932,7 +1008,7 @@ int pa__init(pa_module*m) {
     const char *name;
     char *name_buf = NULL;
     pa_bool_t namereg_fail;
-    pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, mixer_reset = TRUE;
+    pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d;
     pa_source_new_data data;
 
     snd_pcm_info_alloca(&pcm_info);
@@ -988,11 +1064,6 @@ int pa__init(pa_module*m) {
         use_tsched = FALSE;
     }
 
-    if (pa_modargs_get_value_boolean(ma, "mixer_reset", &mixer_reset) < 0) {
-        pa_log("Failed to parse mixer_reset argument.");
-        goto fail;
-    }
-
     u = pa_xnew0(struct userdata, 1);
     u->core = m->core;
     u->module = m;
@@ -1146,6 +1217,8 @@ int pa__init(pa_module*m) {
     u->hw_dB_supported = FALSE;
     u->hw_dB_min = u->hw_dB_max = 0;
     u->hw_volume_min = u->hw_volume_max = 0;
+    u->mixer_seperate_channels = FALSE;
+    pa_cvolume_mute(&u->hardware_volume, u->source->sample_spec.channels);
 
     if (use_tsched)
         fix_tsched_watermark(u);
@@ -1168,67 +1241,51 @@ int pa__init(pa_module*m) {
     if (u->mixer_handle) {
         pa_assert(u->mixer_elem);
 
-        if (snd_mixer_selem_has_capture_volume(u->mixer_elem))
-            if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, FALSE) >= 0 &&
-                snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max) >= 0) {
-
-                pa_bool_t suitable = TRUE;
+        if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) {
+            pa_bool_t suitable = TRUE;
 
+            if (snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max) < 0) {
+                pa_log_info("Failed to get volume range. Falling back to software volume control.");
+                suitable = FALSE;
+            } else {
                 pa_log_info("Volume ranges from %li to %li.", u->hw_volume_min, u->hw_volume_max);
+                pa_assert(u->hw_volume_min < u->hw_volume_max);
+            }
 
-                if (u->hw_volume_min > u->hw_volume_max) {
-
-                    pa_log_info("Minimal volume %li larger than maximum volume %li. Strange stuff Falling back to software volume control.", u->hw_volume_min, u->hw_volume_max);
-                    suitable = FALSE;
-
-                } else if (u->hw_volume_max - u->hw_volume_min < 3) {
-
-                    pa_log_info("Device has less than 4 volume levels. Falling back to software volume control.");
-                    suitable = FALSE;
-
-                } else if (snd_mixer_selem_get_capture_dB_range(u->mixer_elem, &u->hw_dB_min, &u->hw_dB_max) >= 0) {
-
-                    pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", u->hw_dB_min/100.0, u->hw_dB_max/100.0);
-
-                    /* Let's see if this thing actually is useful for muting */
-                    if (u->hw_dB_min > -6000) {
-                        pa_log_info("Device cannot attenuate for more than -60 dB (only %0.2f dB supported), falling back to software volume control.", ((double) u->hw_dB_min) / 100);
-
-                        suitable = FALSE;
-                    } else if (u->hw_dB_max < 0) {
-
-                        pa_log_info("Device is still attenuated at maximum volume setting (%0.2f dB is maximum). Strange stuff. Falling back to software volume control.", ((double) u->hw_dB_max) / 100);
-                        suitable = FALSE;
-
-                    } else if (u->hw_dB_min >= u->hw_dB_max) {
-
-                        pa_log_info("Minimal dB (%0.2f) larger or equal to maximum dB (%0.2f). Strange stuff. Falling back to software volume control.", ((double) u->hw_dB_min) / 100, ((double) u->hw_dB_max) / 100);
-                        suitable = FALSE;
+            if (snd_mixer_selem_get_capture_dB_range(u->mixer_elem, &u->hw_dB_min, &u->hw_dB_max) < 0)
+                pa_log_info("Mixer doesn't support dB information.");
+            else {
+                pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", u->hw_dB_min/100.0, u->hw_dB_max/100.0);
+                pa_assert(u->hw_dB_min < u->hw_dB_max);
+                u->hw_dB_supported = TRUE;
+            }
 
-                    } else
-                        u->hw_dB_supported = TRUE;
-                }
+            if (suitable &&
+                !u->hw_dB_supported &&
+                u->hw_volume_max - u->hw_volume_min < 3) {
 
-                if (suitable) {
-                    u->source->get_volume = source_get_volume_cb;
-                    u->source->set_volume = source_set_volume_cb;
-                    u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL | (u->hw_dB_supported ? PA_SOURCE_DECIBEL_VOLUME : 0);
-                    pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->hw_dB_supported ? "supported" : "not supported");
+                pa_log_info("Device has less than 4 volume levels. Falling back to software volume control.");
+                suitable = FALSE;
+            }
 
-                } else if (mixer_reset) {
-                    pa_log_info("Using software volume control. Trying to reset sound card to 0 dB.");
-                    pa_alsa_0dB_capture(u->mixer_elem);
-                } else
-                    pa_log_info("Using software volume control. Leaving hw mixer controls untouched.");
 
-            }
+            if (suitable) {
+                u->mixer_seperate_channels = pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, FALSE) >= 0;
 
+                u->source->get_volume = source_get_volume_cb;
+                u->source->set_volume = source_set_volume_cb;
+                u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL | (u->hw_dB_supported ? PA_SOURCE_DECIBEL_VOLUME : 0);
+                pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->hw_dB_supported ? "supported" : "not supported");
+            } else
+                pa_log_info("Using software volume control.");
+        }
 
         if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) {
             u->source->get_mute = source_get_mute_cb;
             u->source->set_mute = source_set_mute_cb;
             u->source->flags |= PA_SOURCE_HW_MUTE_CTRL;
-        }
+        } else
+            pa_log_info("Using software mute control.");
 
         u->mixer_fdl = pa_alsa_fdlist_new();
 

commit abd85af93993b99c073e7c5dc833207a7af34946
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 13 13:59:29 2008 +0200

    drop 0db reset functions since they are not necessary anymore

diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c
index be3cdf4..e3e8c85 100644
--- a/src/modules/alsa-util.c
+++ b/src/modules/alsa-util.c
@@ -850,56 +850,6 @@ int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel
     return 0;
 }
 
-void pa_alsa_0dB_playback(snd_mixer_elem_t *elem) {
-    long min, max, v;
-
-    pa_assert(elem);
-
-    /* Try to enable 0 dB if possible. If ALSA cannot do dB, then use
-     * raw volume levels and fix them to 75% */
-
-    if (snd_mixer_selem_set_playback_dB_all(elem, 0, -1) >= 0)
-        return;
-
-    if (snd_mixer_selem_set_playback_dB_all(elem, 0, 1) >= 0)
-        return;
-
-    if (snd_mixer_selem_get_playback_volume_range(elem, &min, &max) < 0)
-        return;
-
-    v = min + ((max - min) * 3) / 4; /* 75% */
-
-    if (v <= min)
-        v = max;
-
-    snd_mixer_selem_set_playback_volume_all(elem, v);
-}
-
-void pa_alsa_0dB_capture(snd_mixer_elem_t *elem) {
-    long min, max, v;
-
-    pa_assert(elem);
-
-    /* Try to enable 0 dB if possible. If ALSA cannot do dB, then use
-     * raw volume levels and fix them to 75% */
-
-    if (snd_mixer_selem_set_capture_dB_all(elem, 0, -1) >= 0)
-        return;
-
-    if (snd_mixer_selem_set_capture_dB_all(elem, 0, 1) >= 0)
-        return;
-
-    if (snd_mixer_selem_get_capture_volume_range(elem, &min, &max) < 0)
-        return;
-
-    v = min + ((max - min) * 3) / 4; /* 75% */
-
-    if (v <= min)
-        v = max;
-
-    snd_mixer_selem_set_capture_volume_all(elem, v);
-}
-
 void pa_alsa_dump(snd_pcm_t *pcm) {
     int err;
     snd_output_t *out;
diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h
index 1b73200..7991a10 100644
--- a/src/modules/alsa-util.h
+++ b/src/modules/alsa-util.h
@@ -80,9 +80,6 @@ snd_pcm_t *pa_alsa_open_by_device_string(
 
 int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel_map, snd_mixer_selem_channel_id_t mixer_map[], pa_bool_t playback);
 
-void pa_alsa_0dB_playback(snd_mixer_elem_t *elem);
-void pa_alsa_0dB_capture(snd_mixer_elem_t *elem);
-
 void pa_alsa_dump(snd_pcm_t *pcm);
 void pa_alsa_dump_status(snd_pcm_t *pcm);
 

commit 916899a9737613a06ff50c9616f1a1016805f8bc
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 13 13:59:50 2008 +0200

    pass force_refresh=FALSE to all volume/mute read invocations

diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c
index 3d731f1..f7d82e4 100644
--- a/src/modules/module-device-restore.c
+++ b/src/modules/module-device-restore.c
@@ -179,8 +179,8 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
 
         name = pa_sprintf_malloc("sink:%s", sink->name);
         entry.channel_map = sink->channel_map;
-        entry.volume = *pa_sink_get_volume(sink);
-        entry.muted = pa_sink_get_mute(sink);
+        entry.volume = *pa_sink_get_volume(sink, FALSE);
+        entry.muted = pa_sink_get_mute(sink, FALSE);
 
     } else {
         pa_source *source;
@@ -192,8 +192,8 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
 
         name = pa_sprintf_malloc("source:%s", source->name);
         entry.channel_map = source->channel_map;
-        entry.volume = *pa_source_get_volume(source);
-        entry.muted = pa_source_get_mute(source);
+        entry.volume = *pa_source_get_volume(source, FALSE);
+        entry.muted = pa_source_get_mute(source, FALSE);
     }
 
     if ((old = read_entry(u, name))) {
diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c
index 4fd0543..97e97dc 100644
--- a/src/modules/module-lirc.c
+++ b/src/modules/module-lirc.c
@@ -122,7 +122,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                     pa_log("Failed to get sink '%s'", u->sink_name);
                 else {
                     int i;
-                    pa_cvolume cv = *pa_sink_get_volume(s);
+                    pa_cvolume cv = *pa_sink_get_volume(s, FALSE);
 
 #define DELTA (PA_VOLUME_NORM/20)
 
@@ -159,7 +159,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
 
                         case MUTE_TOGGLE:
 
-                            pa_sink_set_mute(s, !pa_sink_get_mute(s));
+                            pa_sink_set_mute(s, !pa_sink_get_mute(s, FALSE));
                             break;
 
                         case INVALID:
diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c
index 3f012b7..21f176a 100644
--- a/src/modules/module-mmkbd-evdev.c
+++ b/src/modules/module-mmkbd-evdev.c
@@ -113,7 +113,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                     pa_log("Failed to get sink '%s'", u->sink_name);
                 else {
                     int i;
-                    pa_cvolume cv = *pa_sink_get_volume(s);
+                    pa_cvolume cv = *pa_sink_get_volume(s, FALSE);
 
 #define DELTA (PA_VOLUME_NORM/20)
 
@@ -142,7 +142,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
 
                         case MUTE_TOGGLE:
 
-                            pa_sink_set_mute(s, !pa_sink_get_mute(s));
+                            pa_sink_set_mute(s, !pa_sink_get_mute(s, FALSE));
                             break;
 
                         case INVALID:
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index a80933f..aa05a46 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -1251,8 +1251,8 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b
             nl = 1;
         }
 
-        pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink)));
-        pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink)));
+        pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, FALSE)));
+        pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, FALSE)));
         pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(pa_sink_get_state(sink) == PA_SINK_SUSPENDED));
     }
 
@@ -1265,8 +1265,8 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b
             nl = 1;
         }
 
-        pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source)));
-        pa_strbuf_printf(buf, "set-source-mute %s %s\n", source->name, pa_yes_no(pa_source_get_mute(source)));
+        pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, FALSE)));
+        pa_strbuf_printf(buf, "set-source-mute %s %s\n", source->name, pa_yes_no(pa_source_get_mute(source, FALSE)));
         pa_strbuf_printf(buf, "suspend-source %s %s\n", source->name, pa_yes_no(pa_source_get_state(source) == PA_SOURCE_SUSPENDED));
     }
 
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index c92fca2..4cbe7c3 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -149,8 +149,8 @@ char *pa_sink_list_to_string(pa_core *c) {
             sink->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
             sink->flags & PA_SINK_LATENCY ? "LATENCY " : "",
             state_table[pa_sink_get_state(sink)],
-            pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink)),
-            pa_yes_no(pa_sink_get_mute(sink)),
+            pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)),
+            pa_yes_no(pa_sink_get_mute(sink, FALSE)),
             (double) pa_sink_get_latency(sink) / PA_USEC_PER_MSEC,
             (double) pa_sink_get_requested_latency(sink) / PA_USEC_PER_MSEC, (double) min_latency / PA_USEC_PER_MSEC, (double) max_latency / PA_USEC_PER_MSEC,
             (unsigned long) pa_sink_get_max_request(sink) / 1024,
@@ -222,8 +222,8 @@ char *pa_source_list_to_string(pa_core *c) {
             source->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
             source->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
             state_table[pa_source_get_state(source)],
-            pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source)),
-            pa_yes_no(pa_source_get_mute(source)),
+            pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source, FALSE)),
+            pa_yes_no(pa_source_get_mute(source, FALSE)),
             (double) pa_source_get_latency(source) / PA_USEC_PER_MSEC,
             (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC, (double) min_latency / PA_USEC_PER_MSEC, (double) max_latency / PA_USEC_PER_MSEC,
             (unsigned long) pa_source_get_max_rewind(source) / 1024,
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 0e07276..27e66b2 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -2509,8 +2509,8 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin
         PA_TAG_SAMPLE_SPEC, &fixed_ss,
         PA_TAG_CHANNEL_MAP, &sink->channel_map,
         PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
-        PA_TAG_CVOLUME, pa_sink_get_volume(sink),
-        PA_TAG_BOOLEAN, pa_sink_get_mute(sink),
+        PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
+        PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
         PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
         PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
         PA_TAG_USEC, pa_sink_get_latency(sink),
@@ -2540,8 +2540,8 @@ static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s
         PA_TAG_SAMPLE_SPEC, &fixed_ss,
         PA_TAG_CHANNEL_MAP, &source->channel_map,
         PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
-        PA_TAG_CVOLUME, pa_source_get_volume(source),
-        PA_TAG_BOOLEAN, pa_source_get_mute(source),
+        PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
+        PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
         PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
         PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
         PA_TAG_USEC, pa_source_get_latency(source),

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list