[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v1.0-dev-239-g13d1928

Colin Guthrie gitmailer-noreply at 0pointer.de
Thu Mar 31 03:16:55 PDT 2011


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  6041fc7042dee8e8988fd67fa0b790b9ab4db651 (commit)

- Log -----------------------------------------------------------------
13d1928 vala: ChannelMap has no destroy function.
62f181a bluetooth: Pull a2dp-codecs.h from BlueZ
fce93eb alsa-mixer: Check that the kernel driver returns consistent limits with both snd_mixer_selem_get_*_dB_range() and _ask_*_vol_dB().
44623a3 alsa-mixer: Make sure that SND_MIXER_SCHN_UNKNOWN isn't used when indexing e->masks.
5270785 alsa-mixer: Make probing elements with more than two volume channels fail.
9501504 pactl: Add short output format for list action
8f25f8d pactl: Separate stat and info actions
67760e3 pactl: Add subcommands to the list command
f075059 pactl: Accept more volume specification formats
e72e755 sink-input: Add volume_writable to pa_sink_input.
b358f1c .gitignore: add `.tarball-version`
0bed5ca bluetooth: run `make update-sbc` to pull in build fix for thumb mode
-----------------------------------------------------------------------

Summary of changes:
 .gitignore                                       |    1 +
 PROTOCOL                                         |    2 +-
 src/Makefile.am                                  |    4 +-
 src/modules/alsa/alsa-mixer.c                    |   66 ++++-
 src/modules/bluetooth/a2dp-codecs.h              |  116 +++++++
 src/modules/bluetooth/bluetooth-util.c           |    8 +-
 src/modules/bluetooth/ipc.h                      |   28 --
 src/modules/bluetooth/module-bluetooth-device.c  |    8 +-
 src/modules/bluetooth/sbc/sbc_math.h             |    2 +-
 src/modules/bluetooth/sbc/sbc_primitives_armv6.h |    4 +-
 src/modules/dbus/iface-stream.c                  |   10 +-
 src/modules/module-stream-restore.c              |    6 +-
 src/pulse/introspect.c                           |    6 +-
 src/pulse/introspect.h                           |    2 +-
 src/pulsecore/cli-command.c                      |    2 +-
 src/pulsecore/protocol-native.c                  |    4 +-
 src/pulsecore/sink-input.c                       |   36 +--
 src/pulsecore/sink-input.h                       |    6 +-
 src/utils/pactl.c                                |  393 +++++++++++++++++-----
 vala/libpulse.vapi                               |    2 +-
 20 files changed, 532 insertions(+), 174 deletions(-)
 create mode 100644 src/modules/bluetooth/a2dp-codecs.h

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

commit 0bed5caf3b9fedfce2100cc85de344670ddbb386
Author: Paul Menzel <paulepanter at users.sourceforge.net>
Date:   Tue Mar 29 12:14:27 2011 +0200

    bluetooth: run `make update-sbc` to pull in build fix for thumb mode
    
    This update pulls in commit c495077c [1] to fix a build error.
    
            commit c495077cf8a8c37afd90875ec5a5b16b294be15e
            Author: Siarhei Siamashka <siarhei.siamashka at nokia.com>
            Date:   Tue Mar 29 01:57:39 2011 +0300
    
                sbc: better compatibility with ARM thumb/thumb2
    
                ARM assembly optimizations fail to compile in thumb mode, but are fine
                for thumb2. Update ifdefs in the code to make use of ARM assembly only
                when it is safe and also make sure that no optimizations are missed
                when compiling for thumb2.
    
                The problem was reported by Paul Menzel:
                https://tango.0pointer.de/pipermail/pulseaudio-discuss/2011-February/009022.html
    
    This patch is tested with OpenEmbedded using `minimal-uclibc` for `MACHINE = "at91sam9260ek"`.
    
    Note that changes to ipc.h from 8f3ef04b had to be manually reapplied.
    
    [1] http://git.kernel.org/?p=bluetooth/bluez.git;a=commit;h=c495077cf8a8c37afd90875ec5a5b16b294be15e

diff --git a/src/modules/bluetooth/sbc/sbc_math.h b/src/modules/bluetooth/sbc/sbc_math.h
index 9f126c6..5476860 100644
--- a/src/modules/bluetooth/sbc/sbc_math.h
+++ b/src/modules/bluetooth/sbc/sbc_math.h
@@ -48,7 +48,7 @@ typedef int32_t sbc_fixed_t;
 
 #define SBC_FIXED_0(val) { val = 0; }
 #define MUL(a, b)        ((a) * (b))
-#ifdef __arm__
+#if defined(__arm__) && (!defined(__thumb__) || defined(__thumb2__))
 #define MULA(a, b, res) ({				\
 		int tmp = res;			\
 		__asm__(				\
diff --git a/src/modules/bluetooth/sbc/sbc_primitives_armv6.h b/src/modules/bluetooth/sbc/sbc_primitives_armv6.h
index 1862aed..6a9efe5 100644
--- a/src/modules/bluetooth/sbc/sbc_primitives_armv6.h
+++ b/src/modules/bluetooth/sbc/sbc_primitives_armv6.h
@@ -40,8 +40,8 @@
 
 #if !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) && \
 	defined(__GNUC__) && defined(SBC_HAVE_ARMV6) && \
-	defined(__ARM_EABI__) && !defined(__thumb__) && \
-	!defined(__ARM_NEON__)
+	defined(__ARM_EABI__) && !defined(__ARM_NEON__) && \
+	(!defined(__thumb__) || defined(__thumb2__))
 
 #define SBC_BUILD_WITH_ARMV6_SUPPORT
 

commit b358f1c71d633adcbef02b583120d9ab1a8ac69e
Author: Paul Menzel <paulepanter at users.sourceforge.net>
Date:   Tue Mar 29 11:49:52 2011 +0200

    .gitignore: add `.tarball-version`
    
    `.tarball-version` is created by `.git-version-gen`.
    
    Signed-off-by: Paul Menzel <paulepanter at users.sourceforge.net>

diff --git a/.gitignore b/.gitignore
index 3a840d9..eb33e91 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.tarball-version
 .version
 .*.swp
 ABOUT-NLS

commit e72e75570c97ee9dd1cbce6480d7de8637d470fe
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Sun Mar 27 23:00:26 2011 +0300

    sink-input: Add volume_writable to pa_sink_input.
    
    This is pretty cosmetic change; there's no actual functionality added.
    Previously the volume_writable information was available through the
    pa_sink_input_is_volume_writable() function, but I find it cleaner to have a
    real variable.
    
    The sink input introspection variable name was also changed from
    read_only_volume to volume_writable for consistency.

diff --git a/PROTOCOL b/PROTOCOL
index c2bb209..a15d116 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -212,4 +212,4 @@ New flag at the end of sink input and source output introspection data:
 Two new flags at the end of sink input introspection data:
 
     bool has_volume
-    bool read_only_volume
+    bool volume_writable
diff --git a/src/modules/dbus/iface-stream.c b/src/modules/dbus/iface-stream.c
index e3464fd..d9f1237 100644
--- a/src/modules/dbus/iface-stream.c
+++ b/src/modules/dbus/iface-stream.c
@@ -57,7 +57,6 @@ struct pa_dbusiface_stream {
     pa_proplist *proplist;
 
     pa_bool_t has_volume;
-    pa_bool_t read_only_volume;
 
     pa_dbus_protocol *dbus_protocol;
     pa_subscription *subscription;
@@ -357,6 +356,7 @@ static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *user
 
 static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
     pa_dbusiface_stream *s = userdata;
+    pa_bool_t volume_writable = TRUE;
     DBusMessageIter array_iter;
     int stream_channels = 0;
     dbus_uint32_t *volume = NULL;
@@ -369,12 +369,14 @@ static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessag
     pa_assert(iter);
     pa_assert(s);
 
-    if (!s->has_volume || s->read_only_volume) {
+    volume_writable = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->volume_writable : FALSE;
+
+    if (!s->has_volume || !volume_writable) {
         char *str = stream_to_string(s);
 
         if (!s->has_volume)
             pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str);
-        else if (s->read_only_volume)
+        else if (!volume_writable)
             pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "%s has read-only volume.", str);
         pa_xfree(str);
 
@@ -853,7 +855,6 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, p
     s->sink = pa_sink_ref(sink_input->sink);
     s->sample_rate = sink_input->sample_spec.rate;
     s->has_volume = pa_sink_input_is_volume_readable(sink_input);
-    s->read_only_volume = s->has_volume ? !pa_sink_input_is_volume_writable(sink_input) : FALSE;
 
     if (s->has_volume)
         pa_sink_input_get_volume(sink_input, &s->volume, TRUE);
@@ -891,7 +892,6 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_
     s->mute = FALSE;
     s->proplist = pa_proplist_copy(source_output->proplist);
     s->has_volume = FALSE;
-    s->read_only_volume = FALSE;
     s->dbus_protocol = pa_dbus_protocol_get(source_output->core);
     s->subscription = pa_subscription_new(source_output->core, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscription_cb, s);
     s->send_event_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT],
diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
index df48dce..8edfee0 100644
--- a/src/modules/module-stream-restore.c
+++ b/src/modules/module-stream-restore.c
@@ -1168,7 +1168,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
         }
 
         if (sink_input->save_volume) {
-            pa_assert(pa_sink_input_is_volume_writable(sink_input));
+            pa_assert(sink_input->volume_writable);
 
             entry.channel_map = sink_input->channel_map;
             pa_sink_input_get_volume(sink_input, &entry.volume, FALSE);
@@ -1329,7 +1329,7 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
     if ((e = read_entry(u, name))) {
 
         if (u->restore_volume && e->volume_valid) {
-            if (!pa_sink_input_new_data_is_volume_writable(new_data))
+            if (!new_data->volume_writable)
                 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name);
             else if (new_data->volume_is_set)
                 pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
@@ -1619,7 +1619,7 @@ static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
         }
         pa_xfree(n);
 
-        if (u->restore_volume && e->volume_valid && pa_sink_input_is_volume_writable(si)) {
+        if (u->restore_volume && e->volume_valid && si->volume_writable) {
             pa_cvolume v;
 
             v = e->volume;
diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
index ec27b92..c93fb06 100644
--- a/src/pulse/introspect.c
+++ b/src/pulse/introspect.c
@@ -995,7 +995,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm
 
         while (!pa_tagstruct_eof(t)) {
             pa_sink_input_info i;
-            pa_bool_t mute = FALSE, corked = FALSE, has_volume = FALSE, read_only_volume = FALSE;
+            pa_bool_t mute = FALSE, corked = FALSE, has_volume = FALSE, volume_writable = TRUE;
 
             pa_zero(i);
             i.proplist = pa_proplist_new();
@@ -1016,7 +1016,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm
                 (o->context->version >= 13 && pa_tagstruct_get_proplist(t, i.proplist) < 0) ||
                 (o->context->version >= 19 && pa_tagstruct_get_boolean(t, &corked) < 0) ||
                 (o->context->version >= 20 && (pa_tagstruct_get_boolean(t, &has_volume) < 0 ||
-                                               pa_tagstruct_get_boolean(t, &read_only_volume) < 0))) {
+                                               pa_tagstruct_get_boolean(t, &volume_writable) < 0))) {
 
                 pa_context_fail(o->context, PA_ERR_PROTOCOL);
                 pa_proplist_free(i.proplist);
@@ -1026,7 +1026,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm
             i.mute = (int) mute;
             i.corked = (int) corked;
             i.has_volume = (int) has_volume;
-            i.read_only_volume = (int) read_only_volume;
+            i.volume_writable = (int) volume_writable;
 
             if (o->callback) {
                 pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback;
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index 1cadee5..297b4ba 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -504,7 +504,7 @@ typedef struct pa_sink_input_info {
     pa_proplist *proplist;               /**< Property list \since 0.9.11 */
     int corked;                          /**< Stream corked \since 1.0 */
     int has_volume;                      /**< Stream has volume. If not set, then the meaning of this struct's volume member is unspecified. \since 1.0 */
-    int read_only_volume;                /**< Stream volume can only be read. Although volume control is disabled, the stream volume is still not necessarily constant. \since 1.0 */
+    int volume_writable;                 /**< The volume can be set. If not set, the volume can still change even though clients can't control the volume. \since 1.0 */
 } pa_sink_input_info;
 
 /** Callback prototype for pa_context_get_sink_input_info() and friends*/
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index de4995e..17b0e15 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -585,7 +585,7 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb
         return -1;
     }
 
-    if (!pa_sink_input_is_volume_writable(si)) {
+    if (!si->volume_writable) {
         pa_strbuf_puts(buf, "This sink input's volume can't be changed.\n");
         return -1;
     }
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index bb4be72..4952ee4 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -3089,7 +3089,7 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t,
         pa_tagstruct_put_boolean(t, (pa_sink_input_get_state(s) == PA_SINK_INPUT_CORKED));
     if (c->version >= 20) {
         pa_tagstruct_put_boolean(t, has_volume);
-        pa_tagstruct_put_boolean(t, has_volume ? !pa_sink_input_is_volume_writable(s) : FALSE);
+        pa_tagstruct_put_boolean(t, s->volume_writable);
     }
 }
 
@@ -3472,7 +3472,7 @@ static void command_set_volume(
         pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
         pa_source_set_volume(source, &volume, TRUE);
     } else if (si) {
-        CHECK_VALIDITY(c->pstream, pa_sink_input_is_volume_writable(si), tag, PA_ERR_INVALID);
+        CHECK_VALIDITY(c->pstream, si->volume_writable, tag, PA_ERR_BADSTATE);
         CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
 
         pa_log_debug("Client %s changes volume of sink input %s.",
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index e0e81be..46f26f9 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -88,6 +88,7 @@ pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data
     pa_zero(*data);
     data->resample_method = PA_RESAMPLER_INVALID;
     data->proplist = pa_proplist_new();
+    data->volume_writable = TRUE;
 
     return data;
 }
@@ -106,21 +107,9 @@ void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const
         data->channel_map = *map;
 }
 
-pa_bool_t pa_sink_input_new_data_is_volume_writable(pa_sink_input_new_data *data) {
-    pa_assert(data);
-
-    if (data->flags & PA_SINK_INPUT_PASSTHROUGH)
-        return FALSE;
-
-    if (data->origin_sink && (data->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
-        return FALSE;
-
-    return TRUE;
-}
-
 void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
     pa_assert(data);
-    pa_assert(pa_sink_input_new_data_is_volume_writable(data));
+    pa_assert(data->volume_writable);
 
     if ((data->volume_is_set = !!volume))
         data->volume = *volume;
@@ -209,10 +198,12 @@ int pa_sink_input_new(
     if (data->client)
         pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist);
 
+    if (data->origin_sink && (data->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+        data->volume_writable = FALSE;
+
     if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data)) < 0)
         return r;
 
-    pa_assert(!data->volume_is_set || pa_sink_input_new_data_is_volume_writable(data));
     pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID);
 
     if (!data->sink) {
@@ -353,6 +344,7 @@ int pa_sink_input_new(
     i->real_ratio = i->reference_ratio = data->volume;
     pa_cvolume_reset(&i->soft_volume, i->sample_spec.channels);
     pa_cvolume_reset(&i->real_ratio, i->sample_spec.channels);
+    i->volume_writable = data->volume_writable;
     i->save_volume = data->save_volume;
     i->save_sink = data->save_sink;
     i->save_muted = data->save_muted;
@@ -1026,7 +1018,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
     pa_assert(volume);
     pa_assert(pa_cvolume_valid(volume));
     pa_assert(volume->channels == 1 || pa_cvolume_compatible(volume, &i->sample_spec));
-    pa_assert(pa_sink_input_is_volume_writable(i));
+    pa_assert(i->volume_writable);
 
     if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
         v = i->sink->reference_volume;
@@ -1104,20 +1096,6 @@ pa_bool_t pa_sink_input_is_volume_readable(pa_sink_input *i) {
 }
 
 /* Called from main context */
-pa_bool_t pa_sink_input_is_volume_writable(pa_sink_input *i) {
-    pa_sink_input_assert_ref(i);
-    pa_assert_ctl_context();
-
-    if (i->flags & PA_SINK_INPUT_PASSTHROUGH)
-        return FALSE;
-
-    if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
-        return FALSE;
-
-    return TRUE;
-}
-
-/* Called from main context */
 pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute) {
     pa_sink_input_assert_ref(i);
     pa_assert_ctl_context();
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 588005f..11f6608 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -104,6 +104,8 @@ struct pa_sink_input {
 
     pa_cvolume volume_factor_sink; /* A second volume factor in format of the sink this stream is connected to */
 
+    pa_bool_t volume_writable:1;
+
     pa_bool_t muted:1;
 
     /* if TRUE then the source we are connected to and/or the volume
@@ -289,13 +291,14 @@ typedef struct pa_sink_input_new_data {
 
     pa_bool_t volume_is_absolute:1;
 
+    pa_bool_t volume_writable:1;
+
     pa_bool_t save_sink:1, save_volume:1, save_muted:1;
 } pa_sink_input_new_data;
 
 pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data);
 void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec);
 void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map);
-pa_bool_t pa_sink_input_new_data_is_volume_writable(pa_sink_input_new_data *data);
 void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume);
 void pa_sink_input_new_data_apply_volume_factor(pa_sink_input_new_data *data, const pa_cvolume *volume_factor);
 void pa_sink_input_new_data_apply_volume_factor_sink(pa_sink_input_new_data *data, const pa_cvolume *volume_factor);
@@ -341,7 +344,6 @@ void pa_sink_input_kill(pa_sink_input*i);
 pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency);
 
 pa_bool_t pa_sink_input_is_volume_readable(pa_sink_input *i);
-pa_bool_t pa_sink_input_is_volume_writable(pa_sink_input *i);
 void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute);
 pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute);
 

commit f07505998ebea6a6d181fe36408646d94b5f2491
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Sat Mar 26 17:15:40 2011 +0100

    pactl: Accept more volume specification formats
    
    With this you can specify the volume with 6554, 10%, 0.001 or -60dB,
    all resulting in the same volume change.

diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index ad5c0b8..9b6050a 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -65,6 +65,14 @@ static uint32_t module_index;
 static pa_bool_t suspend;
 static pa_bool_t mute;
 static pa_volume_t volume;
+static enum volume_flags {
+    VOL_UINT     = 0,
+    VOL_PERCENT  = 1,
+    VOL_LINEAR   = 2,
+    VOL_DECIBEL  = 3,
+    VOL_ABSOLUTE = 0 << 4,
+    VOL_RELATIVE = 1 << 4,
+} volume_flags;
 
 static pa_proplist *proplist = NULL;
 
@@ -683,6 +691,78 @@ static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
     complete_action();
 }
 
+static void volume_relative_adjust(pa_cvolume *cv) {
+    pa_assert((volume_flags & VOL_RELATIVE) == VOL_RELATIVE);
+
+    /* Relative volume change is additive in case of UINT or PERCENT
+     * and multiplicative for LINEAR or DECIBEL */
+    if ((volume_flags & 0x0F) == VOL_UINT || (volume_flags & 0x0F) == VOL_PERCENT) {
+        pa_volume_t v = pa_cvolume_avg(cv);
+        v = v + volume < PA_VOLUME_NORM ? PA_VOLUME_MUTED : v + volume - PA_VOLUME_NORM;
+        pa_cvolume_set(cv, 1, v);
+    }
+    if ((volume_flags & 0x0F) == VOL_LINEAR || (volume_flags & 0x0F) == VOL_DECIBEL) {
+        pa_sw_cvolume_multiply_scalar(cv, cv, volume);
+    }
+}
+
+static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
+    pa_cvolume cv;
+
+    if (is_last < 0) {
+        pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last)
+        return;
+
+    pa_assert(i);
+
+    cv = i->volume;
+    volume_relative_adjust(&cv);
+    pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL));
+}
+
+static void get_source_volume_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
+    pa_cvolume cv;
+
+    if (is_last < 0) {
+        pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last)
+        return;
+
+    pa_assert(i);
+
+    cv = i->volume;
+    volume_relative_adjust(&cv);
+    pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL));
+}
+
+static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
+    pa_cvolume cv;
+
+    if (is_last < 0) {
+        pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last)
+        return;
+
+    pa_assert(i);
+
+    cv = i->volume;
+    volume_relative_adjust(&cv);
+    pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &cv, simple_callback, NULL));
+}
+
 static void stream_state_callback(pa_stream *s, void *userdata) {
     pa_assert(s);
 
@@ -893,34 +973,40 @@ static void context_state_callback(pa_context *c, void *userdata) {
                     pa_operation_unref(pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL));
                     break;
 
-                case SET_SINK_VOLUME: {
-                    pa_cvolume v;
-
-                    pa_cvolume_set(&v, 1, volume);
-                    pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL));
+                case SET_SINK_VOLUME:
+                    if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+                        pa_operation_unref(pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL));
+                    } else {
+                        pa_cvolume v;
+                        pa_cvolume_set(&v, 1, volume);
+                        pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL));
+                    }
                     break;
-                }
-
-                case SET_SOURCE_VOLUME: {
-                    pa_cvolume v;
 
-                    pa_cvolume_set(&v, 1, volume);
-                    pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL));
+                case SET_SOURCE_VOLUME:
+                    if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+                        pa_operation_unref(pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL));
+                    } else {
+                        pa_cvolume v;
+                        pa_cvolume_set(&v, 1, volume);
+                        pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL));
+                    }
                     break;
-                }
 
-                case SET_SINK_INPUT_VOLUME: {
-                    pa_cvolume v;
-
-                    pa_cvolume_set(&v, 1, volume);
-                    pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL));
+                case SET_SINK_INPUT_VOLUME:
+                    if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+                        pa_operation_unref(pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL));
+                    } else {
+                        pa_cvolume v;
+                        pa_cvolume_set(&v, 1, volume);
+                        pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL));
+                    }
                     break;
-                }
 
-               case SUBSCRIBE:
-                   pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
+                case SUBSCRIBE:
+                    pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
 
-                   pa_operation_unref(pa_context_subscribe(
+                    pa_operation_unref(pa_context_subscribe(
                                               c,
                                               PA_SUBSCRIPTION_MASK_SINK|
                                               PA_SUBSCRIPTION_MASK_SOURCE|
@@ -933,7 +1019,7 @@ static void context_state_callback(pa_context *c, void *userdata) {
                                               PA_SUBSCRIPTION_MASK_CARD,
                                               NULL,
                                               NULL));
-                   break;
+                    break;
 
                 default:
                     pa_assert_not_reached();
@@ -956,6 +1042,61 @@ static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig
     quit(0);
 }
 
+static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flags *vol_flags) {
+    double v;
+    char *vs;
+
+    pa_assert(vol_spec);
+    pa_assert(vol);
+    pa_assert(vol_flags);
+
+    vs = pa_xstrdup(vol_spec);
+
+    *vol_flags = (pa_startswith(vs, "+") || pa_startswith(vs, "-")) ? VOL_RELATIVE : VOL_ABSOLUTE;
+    if (strchr(vs, '.'))
+        *vol_flags |= VOL_LINEAR;
+    if (pa_endswith(vs, "%")) {
+        *vol_flags |= VOL_PERCENT;
+        vs[strlen(vs)-1] = 0;
+    }
+    if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) {
+        *vol_flags |= VOL_DECIBEL;
+        vs[strlen(vs)-2] = 0;
+    }
+
+    if (pa_atod(vs, &v) < 0) {
+        pa_log(_("Invalid volume specification"));
+        pa_xfree(vs);
+        return -1;
+    }
+
+    pa_xfree(vs);
+
+    if ((*vol_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+        if ((*vol_flags & 0x0F) == VOL_UINT)
+            v += (double) PA_VOLUME_NORM;
+        if ((*vol_flags & 0x0F) == VOL_PERCENT)
+            v += 100.0;
+        if ((*vol_flags & 0x0F) == VOL_LINEAR)
+            v += 1.0;
+    }
+    if ((*vol_flags & 0x0F) == VOL_PERCENT)
+        v = v * (double) PA_VOLUME_NORM / 100;
+    if ((*vol_flags & 0x0F) == VOL_LINEAR)
+        v = pa_sw_volume_from_linear(v);
+    if ((*vol_flags & 0x0F) == VOL_DECIBEL)
+        v = pa_sw_volume_from_dB(v);
+
+    if (!PA_VOLUME_IS_VALID((pa_volume_t) v)) {
+        pa_log(_("Volume outside permissible range.\n"));
+        return -1;
+    }
+
+    *vol = (pa_volume_t) v;
+
+    return 0;
+}
+
 static void help(const char *argv0) {
 
     printf(_("%s [options] stat\n"
@@ -1235,7 +1376,6 @@ int main(int argc, char *argv[]) {
             port_name = pa_xstrdup(argv[optind+2]);
 
         } else if (pa_streq(argv[optind], "set-sink-volume")) {
-            uint32_t v;
             action = SET_SINK_VOLUME;
 
             if (argc != optind+3) {
@@ -1243,21 +1383,12 @@ int main(int argc, char *argv[]) {
                 goto quit;
             }
 
-            if (pa_atou(argv[optind+2], &v) < 0) {
-                pa_log(_("Invalid volume specification"));
-                goto quit;
-            }
+            sink_name = pa_xstrdup(argv[optind+1]);
 
-            if (!PA_VOLUME_IS_VALID(v)) {
-                pa_log(_("Volume outside permissible range.\n"));
+            if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
                 goto quit;
-            }
-
-            sink_name = pa_xstrdup(argv[optind+1]);
-            volume = (pa_volume_t) v;
 
         } else if (pa_streq(argv[optind], "set-source-volume")) {
-            uint32_t v;
             action = SET_SOURCE_VOLUME;
 
             if (argc != optind+3) {
@@ -1265,21 +1396,12 @@ int main(int argc, char *argv[]) {
                 goto quit;
             }
 
-            if (pa_atou(argv[optind+2], &v) < 0) {
-                pa_log(_("Invalid volume specification"));
-                goto quit;
-            }
+            source_name = pa_xstrdup(argv[optind+1]);
 
-            if (!PA_VOLUME_IS_VALID(v)) {
-                pa_log(_("Volume outside permissible range.\n"));
+            if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
                 goto quit;
-            }
-
-            source_name = pa_xstrdup(argv[optind+1]);
-            volume = (pa_volume_t) v;
 
         } else if (pa_streq(argv[optind], "set-sink-input-volume")) {
-            uint32_t v;
             action = SET_SINK_INPUT_VOLUME;
 
             if (argc != optind+3) {
@@ -1292,17 +1414,8 @@ int main(int argc, char *argv[]) {
                 goto quit;
             }
 
-            if (pa_atou(argv[optind+2], &v) < 0) {
-                pa_log(_("Invalid volume specification"));
+            if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
                 goto quit;
-            }
-
-            if (!PA_VOLUME_IS_VALID(v)) {
-                pa_log(_("Volume outside permissible range.\n"));
-                goto quit;
-            }
-
-            volume = (pa_volume_t) v;
 
         } else if (pa_streq(argv[optind], "set-sink-mute")) {
             int b;
@@ -1314,7 +1427,7 @@ int main(int argc, char *argv[]) {
             }
 
             if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
-                pa_log(_("Invalid volume specification"));
+                pa_log(_("Invalid mute specification"));
                 goto quit;
             }
 
@@ -1331,7 +1444,7 @@ int main(int argc, char *argv[]) {
             }
 
             if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
-                pa_log(_("Invalid volume specification"));
+                pa_log(_("Invalid mute specification"));
                 goto quit;
             }
 
@@ -1353,7 +1466,7 @@ int main(int argc, char *argv[]) {
             }
 
             if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
-                pa_log(_("Invalid volume specification"));
+                pa_log(_("Invalid mute specification"));
                 goto quit;
             }
 

commit 67760e3193533b169f6f96f0b4f297150f82d758
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Sat Mar 26 17:15:41 2011 +0100

    pactl: Add subcommands to the list command

diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index 9b6050a..e3c2aa2 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -48,6 +48,7 @@ static pa_context *context = NULL;
 static pa_mainloop_api *mainloop_api = NULL;
 
 static char
+    *list_type = NULL,
     *sample_name = NULL,
     *sink_name = NULL,
     *source_name = NULL,
@@ -908,15 +909,36 @@ static void context_state_callback(pa_context *c, void *userdata) {
                     break;
 
                 case LIST:
-                    actions = 8;
-                    pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
+                    if (list_type) {
+                        if (pa_streq(list_type, "modules"))
+                            pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
+                        else if (pa_streq(list_type, "sinks"))
+                            pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
+                        else if (pa_streq(list_type, "sources"))
+                            pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
+                        else if (pa_streq(list_type, "sink-inputs"))
+                            pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
+                        else if (pa_streq(list_type, "source-outputs"))
+                            pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
+                        else if (pa_streq(list_type, "clients"))
+                            pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
+                        else if (pa_streq(list_type, "samples"))
+                            pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
+                        else if (pa_streq(list_type, "cards"))
+                            pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
+                        else
+                            pa_assert_not_reached();
+                    } else {
+                        actions = 8;
+                        pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
+                    }
                     break;
 
                 case MOVE_SINK_INPUT:
@@ -1100,7 +1122,7 @@ static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flag
 static void help(const char *argv0) {
 
     printf(_("%s [options] stat\n"
-             "%s [options] list\n"
+             "%s [options] list [TYPE]\n"
              "%s [options] exit\n"
              "%s [options] upload-sample FILENAME [NAME]\n"
              "%s [options] play-sample NAME [SINK]\n"
@@ -1137,7 +1159,7 @@ enum {
 };
 
 int main(int argc, char *argv[]) {
-    pa_mainloop* m = NULL;
+    pa_mainloop *m = NULL;
     int ret = 1, c;
     char *server = NULL, *bn;
 
@@ -1201,11 +1223,26 @@ int main(int argc, char *argv[]) {
     if (optind < argc) {
         if (pa_streq(argv[optind], "stat"))
             action = STAT;
+
         else if (pa_streq(argv[optind], "exit"))
             action = EXIT;
-        else if (pa_streq(argv[optind], "list"))
+
+        else if (pa_streq(argv[optind], "list")) {
             action = LIST;
-        else if (pa_streq(argv[optind], "upload-sample")) {
+
+            for (int i = optind+1; i < argc; i++){
+                if (pa_streq(argv[i], "modules") || pa_streq(argv[i], "clients") ||
+                    pa_streq(argv[i], "sinks")   || pa_streq(argv[i], "sink-inputs") ||
+                    pa_streq(argv[i], "sources") || pa_streq(argv[i], "source-outputs") ||
+                    pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards")) {
+                    list_type = pa_xstrdup(argv[i]);
+                } else {
+                    pa_log(_("Specify nothing, or one of: %s"), "modules, sinks, sources, sink-inputs, source-outputs, clients, samples, cards");
+                    goto quit;
+                }
+            }
+
+        } else if (pa_streq(argv[optind], "upload-sample")) {
             struct SF_INFO sfi;
             action = UPLOAD_SAMPLE;
 
@@ -1235,7 +1272,7 @@ int main(int argc, char *argv[]) {
 
             if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
                 if (sample_spec.channels > 2)
-                     pa_log(_("Warning: Failed to determine sample specification from file."));
+                    pa_log(_("Warning: Failed to determine sample specification from file."));
                 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
             }
 
@@ -1529,12 +1566,14 @@ quit:
     }
 
     pa_xfree(server);
+    pa_xfree(list_type);
     pa_xfree(sample_name);
     pa_xfree(sink_name);
     pa_xfree(source_name);
     pa_xfree(module_args);
     pa_xfree(card_name);
     pa_xfree(profile_name);
+    pa_xfree(port_name);
 
     if (sndfile)
         sf_close(sndfile);

commit 8f25f8dc7d41cec7f644391b2a76613cd994133b
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Sat Mar 26 17:15:42 2011 +0100

    pactl: Separate stat and info actions

diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index e3c2aa2..cfa96fe 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -90,6 +90,7 @@ static enum {
     NONE,
     EXIT,
     STAT,
+    INFO,
     UPLOAD_SAMPLE,
     PLAY_SAMPLE,
     REMOVE_SAMPLE,
@@ -882,8 +883,10 @@ static void context_state_callback(pa_context *c, void *userdata) {
         case PA_CONTEXT_READY:
             switch (action) {
                 case STAT:
-                    actions = 2;
                     pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
+                    break;
+
+                case INFO:
                     pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
                     break;
 
@@ -1122,6 +1125,7 @@ static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flag
 static void help(const char *argv0) {
 
     printf(_("%s [options] stat\n"
+             "%s [options] info\n"
              "%s [options] list [TYPE]\n"
              "%s [options] exit\n"
              "%s [options] upload-sample FILENAME [NAME]\n"
@@ -1151,7 +1155,7 @@ static void help(const char *argv0) {
            argv0, argv0, argv0, argv0, argv0,
            argv0, argv0, argv0, argv0, argv0,
            argv0, argv0, argv0, argv0, argv0,
-           argv0, argv0);
+           argv0, argv0, argv0);
 }
 
 enum {
@@ -1224,6 +1228,9 @@ int main(int argc, char *argv[]) {
         if (pa_streq(argv[optind], "stat"))
             action = STAT;
 
+        else if (pa_streq(argv[optind], "info"))
+            action = INFO;
+
         else if (pa_streq(argv[optind], "exit"))
             action = EXIT;
 

commit 9501504859cf5f8ab5b700e89c831e8c34c9bae3
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Sat Mar 26 17:15:43 2011 +0100

    pactl: Add short output format for list action

diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index cfa96fe..194183d 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -62,6 +62,7 @@ static uint32_t
     sink_input_idx = PA_INVALID_INDEX,
     source_output_idx = PA_INVALID_INDEX;
 
+static pa_bool_t short_list_format = FALSE;
 static uint32_t module_index;
 static pa_bool_t suspend;
 static pa_bool_t mute;
@@ -237,10 +238,20 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_
 
     pa_assert(i);
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
     nl = TRUE;
 
+    if (short_list_format) {
+        printf("%u\t%s\t%s\t%s\t%s\n",
+               i->index,
+               i->name,
+               pa_strnull(i->driver),
+               pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
+               state_table[1+i->state]);
+        return;
+    }
+
     printf(_("Sink #%u\n"
              "\tState: %s\n"
              "\tName: %s\n"
@@ -329,10 +340,20 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int
 
     pa_assert(i);
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
     nl = TRUE;
 
+    if (short_list_format) {
+        printf("%u\t%s\t%s\t%s\t%s\n",
+               i->index,
+               i->name,
+               pa_strnull(i->driver),
+               pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
+               state_table[1+i->state]);
+        return;
+    }
+
     printf(_("Source #%u\n"
              "\tState: %s\n"
              "\tName: %s\n"
@@ -407,12 +428,17 @@ static void get_module_info_callback(pa_context *c, const pa_module_info *i, int
 
     pa_assert(i);
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
     nl = TRUE;
 
     pa_snprintf(t, sizeof(t), "%u", i->n_used);
 
+    if (short_list_format) {
+        printf("%u\t%s\t%s\t\n", i->index, i->name, i->argument ? i->argument : "");
+        return;
+    }
+
     printf(_("Module #%u\n"
              "\tName: %s\n"
              "\tArgument: %s\n"
@@ -444,12 +470,20 @@ static void get_client_info_callback(pa_context *c, const pa_client_info *i, int
 
     pa_assert(i);
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
     nl = TRUE;
 
     pa_snprintf(t, sizeof(t), "%u", i->owner_module);
 
+    if (short_list_format) {
+        printf("%u\t%s\t%s\n",
+               i->index,
+               pa_strnull(i->driver),
+               pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
+        return;
+    }
+
     printf(_("Client #%u\n"
              "\tDriver: %s\n"
              "\tOwner Module: %s\n"
@@ -479,12 +513,17 @@ static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_
 
     pa_assert(i);
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
     nl = TRUE;
 
     pa_snprintf(t, sizeof(t), "%u", i->owner_module);
 
+    if (short_list_format) {
+        printf("%u\t%s\t%s\n", i->index, i->name, pa_strnull(i->driver));
+        return;
+    }
+
     printf(_("Card #%u\n"
              "\tName: %s\n"
              "\tDriver: %s\n"
@@ -528,13 +567,23 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info
 
     pa_assert(i);
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
     nl = TRUE;
 
     pa_snprintf(t, sizeof(t), "%u", i->owner_module);
     pa_snprintf(k, sizeof(k), "%u", i->client);
 
+    if (short_list_format) {
+        printf("%u\t%u\t%s\t%s\t%s\n",
+               i->index,
+               i->sink,
+               i->client != PA_INVALID_INDEX ? k : "-",
+               pa_strnull(i->driver),
+               pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
+        return;
+    }
+
     printf(_("Sink Input #%u\n"
              "\tDriver: %s\n"
              "\tOwner Module: %s\n"
@@ -586,7 +635,7 @@ static void get_source_output_info_callback(pa_context *c, const pa_source_outpu
 
     pa_assert(i);
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
     nl = TRUE;
 
@@ -594,6 +643,16 @@ static void get_source_output_info_callback(pa_context *c, const pa_source_outpu
     pa_snprintf(t, sizeof(t), "%u", i->owner_module);
     pa_snprintf(k, sizeof(k), "%u", i->client);
 
+    if (short_list_format) {
+        printf("%u\t%u\t%s\t%s\t%s\n",
+               i->index,
+               i->source,
+               i->client != PA_INVALID_INDEX ? k : "-",
+               pa_strnull(i->driver),
+               pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
+        return;
+    }
+
     printf(_("Source Output #%u\n"
              "\tDriver: %s\n"
              "\tOwner Module: %s\n"
@@ -637,12 +696,21 @@ static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int
 
     pa_assert(i);
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
     nl = TRUE;
 
     pa_bytes_snprint(t, sizeof(t), i->bytes);
 
+    if (short_list_format) {
+        printf("%u\t%s\t%s\t%0.3f\n",
+               i->index,
+               i->name,
+               pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : "-",
+               (double) i->duration/1000000.0);
+        return;
+    }
+
     printf(_("Sample #%u\n"
              "\tName: %s\n"
              "\tSample Specification: %s\n"
@@ -1126,7 +1194,7 @@ static void help(const char *argv0) {
 
     printf(_("%s [options] stat\n"
              "%s [options] info\n"
-             "%s [options] list [TYPE]\n"
+             "%s [options] list [short] [TYPE]\n"
              "%s [options] exit\n"
              "%s [options] upload-sample FILENAME [NAME]\n"
              "%s [options] play-sample NAME [SINK]\n"
@@ -1243,6 +1311,8 @@ int main(int argc, char *argv[]) {
                     pa_streq(argv[i], "sources") || pa_streq(argv[i], "source-outputs") ||
                     pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards")) {
                     list_type = pa_xstrdup(argv[i]);
+                } else if (pa_streq(argv[i], "short")) {
+                    short_list_format = TRUE;
                 } else {
                     pa_log(_("Specify nothing, or one of: %s"), "modules, sinks, sources, sink-inputs, source-outputs, clients, samples, cards");
                     goto quit;

commit 527078523815587bfd021bc1d10782403e9b3e84
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Wed Mar 23 14:52:48 2011 +0200

    alsa-mixer: Make probing elements with more than two volume channels fail.
    
    This is just a quick hack to prevent array overflow. Correct fix would be to
    implement support for more channels.

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 3b13879..eb8b943 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -1477,6 +1477,22 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
                         return -1;
                     }
 
+                    if (e->n_channels > 2) {
+                        /* FIXME: In some places code like this is used:
+                         *
+                         *     e->masks[alsa_channel_ids[p]][e->n_channels-1]
+                         *
+                         * The definition of e->masks is
+                         *
+                         *     pa_channel_position_mask_t masks[SND_MIXER_SCHN_LAST][2];
+                         *
+                         * Since the array size is fixed at 2, we obviously
+                         * don't support elements with more than two
+                         * channels... */
+                        pa_log_warn("Volume element %s has %u channels. That's too much! I can't handle that!", e->alsa_name, e->n_channels);
+                        return -1;
+                    }
+
                     if (!e->override_map) {
                         for (p = PA_CHANNEL_POSITION_FRONT_LEFT; p < PA_CHANNEL_POSITION_MAX; p++) {
                             pa_bool_t has_channel;

commit 44623a347de67100e9d1059b682f0dcfb89bd273
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Wed Mar 23 12:03:43 2011 +0200

    alsa-mixer: Make sure that SND_MIXER_SCHN_UNKNOWN isn't used when indexing e->masks.
    
    SND_MIXER_SCHN_UNKNOWN is defined as -1, so that's not a good array index...

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index eb8b943..b134068 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -1453,8 +1453,13 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
                     e->n_channels = 1;
 
                     if (!e->override_map) {
-                        for (p = PA_CHANNEL_POSITION_FRONT_LEFT; p < PA_CHANNEL_POSITION_MAX; p++)
+                        for (p = PA_CHANNEL_POSITION_FRONT_LEFT; p < PA_CHANNEL_POSITION_MAX; p++) {
+                            if (alsa_channel_ids[p] == SND_MIXER_SCHN_UNKNOWN)
+                                continue;
+
                             e->masks[alsa_channel_ids[p]][e->n_channels-1] = 0;
+                        }
+
                         e->masks[SND_MIXER_SCHN_MONO][e->n_channels-1] = PA_CHANNEL_POSITION_MASK_ALL;
                     }
 
@@ -1510,8 +1515,12 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
                     }
 
                     e->merged_mask = 0;
-                    for (p = PA_CHANNEL_POSITION_FRONT_LEFT; p < PA_CHANNEL_POSITION_MAX; p++)
+                    for (p = PA_CHANNEL_POSITION_FRONT_LEFT; p < PA_CHANNEL_POSITION_MAX; p++) {
+                        if (alsa_channel_ids[p] == SND_MIXER_SCHN_UNKNOWN)
+                            continue;
+
                         e->merged_mask |= e->masks[alsa_channel_ids[p]][e->n_channels-1];
+                    }
                 }
             }
         }

commit fce93eb6254a12ff16b20426017efd540b982ef7
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Tue Mar 22 12:23:19 2011 +0200

    alsa-mixer: Check that the kernel driver returns consistent limits with both snd_mixer_selem_get_*_dB_range() and _ask_*_vol_dB().
    
    The check is inspired by a driver that returned higher dB limit from
    snd_mixer_selem_get_playback_dB_range() than what _ask_playback_vol_dB()
    returned at maximum integer volume.

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index b134068..f236da0 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -1398,6 +1398,43 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
                 else
                     e->has_dB = snd_mixer_selem_get_capture_dB_range(me, &min_dB, &max_dB) >= 0;
 
+                /* Check that the kernel driver returns consistent limits with
+                 * both _get_*_dB_range() and _ask_*_vol_dB(). */
+                if (e->has_dB && !e->db_fix) {
+                    long min_dB_checked = 0;
+                    long max_dB_checked = 0;
+
+                    if (e->direction == PA_ALSA_DIRECTION_OUTPUT)
+                        r = snd_mixer_selem_ask_playback_vol_dB(me, e->min_volume, &min_dB_checked);
+                    else
+                        r = snd_mixer_selem_ask_capture_vol_dB(me, e->min_volume, &min_dB_checked);
+
+                    if (r < 0) {
+                        pa_log_warn("Failed to query the dB value for %s at volume level %li", e->alsa_name, e->min_volume);
+                        return -1;
+                    }
+
+                    if (e->direction == PA_ALSA_DIRECTION_OUTPUT)
+                        r = snd_mixer_selem_ask_playback_vol_dB(me, e->max_volume, &max_dB_checked);
+                    else
+                        r = snd_mixer_selem_ask_capture_vol_dB(me, e->max_volume, &max_dB_checked);
+
+                    if (r < 0) {
+                        pa_log_warn("Failed to query the dB value for %s at volume level %li", e->alsa_name, e->max_volume);
+                        return -1;
+                    }
+
+                    if (min_dB != min_dB_checked || max_dB != max_dB_checked) {
+                        pa_log_warn("Your kernel driver is broken: the reported dB range for %s (from %0.2f dB to %0.2f dB) "
+                                    "doesn't match the dB values at minimum and maximum volume levels: %0.2f dB at level %li, "
+                                    "%0.2f dB at level %li.",
+                                    e->alsa_name,
+                                    min_dB / 100.0, max_dB / 100.0,
+                                    min_dB_checked / 100.0, e->min_volume, max_dB_checked / 100.0, e->max_volume);
+                        return -1;
+                    }
+                }
+
                 if (e->has_dB) {
 #ifdef HAVE_VALGRIND_MEMCHECK_H
                     VALGRIND_MAKE_MEM_DEFINED(&min_dB, sizeof(min_dB));

commit 62f181aa2834ceea1d759e75d59c4feae0f9b9f7
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Thu Mar 31 00:56:20 2011 +0530

    bluetooth: Pull a2dp-codecs.h from BlueZ
    
    This pulls a2dp-codecs.h from BlueZ which contains the capabilities
    structures for SBC and MPEG. We currently have these manually added to
    ipc.h, so pulling this header makes our files identical to upstream.

diff --git a/src/Makefile.am b/src/Makefile.am
index f3717ce..3bec5e8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1847,7 +1847,9 @@ libbluetooth_sbc_la_LIBADD = $(MODULE_LIBADD)
 libbluetooth_sbc_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/src/modules/bluetooth/sbc
 BLUETOOTH_SBC_FILES = $(subst modules/bluetooth/,,$(libbluetooth_sbc_la_SOURCES))
 
-libbluetooth_ipc_la_SOURCES = modules/bluetooth/ipc.c modules/bluetooth/ipc.h
+libbluetooth_ipc_la_SOURCES = \
+		modules/bluetooth/a2dp-codecs.h \
+		modules/bluetooth/ipc.c modules/bluetooth/ipc.h
 libbluetooth_ipc_la_LDFLAGS = -avoid-version
 libbluetooth_ipc_la_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la
 libbluetooth_ipc_la_CFLAGS = $(AM_CFLAGS)
diff --git a/src/modules/bluetooth/a2dp-codecs.h b/src/modules/bluetooth/a2dp-codecs.h
new file mode 100644
index 0000000..e44634e
--- /dev/null
+++ b/src/modules/bluetooth/a2dp-codecs.h
@@ -0,0 +1,116 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define A2DP_CODEC_SBC			0x00
+#define A2DP_CODEC_MPEG12		0x01
+#define A2DP_CODEC_MPEG24		0x02
+#define A2DP_CODEC_ATRAC		0x03
+
+#define SBC_SAMPLING_FREQ_16000		(1 << 3)
+#define SBC_SAMPLING_FREQ_32000		(1 << 2)
+#define SBC_SAMPLING_FREQ_44100		(1 << 1)
+#define SBC_SAMPLING_FREQ_48000		1
+
+#define SBC_CHANNEL_MODE_MONO		(1 << 3)
+#define SBC_CHANNEL_MODE_DUAL_CHANNEL	(1 << 2)
+#define SBC_CHANNEL_MODE_STEREO		(1 << 1)
+#define SBC_CHANNEL_MODE_JOINT_STEREO	1
+
+#define SBC_BLOCK_LENGTH_4		(1 << 3)
+#define SBC_BLOCK_LENGTH_8		(1 << 2)
+#define SBC_BLOCK_LENGTH_12		(1 << 1)
+#define SBC_BLOCK_LENGTH_16		1
+
+#define SBC_SUBBANDS_4			(1 << 1)
+#define SBC_SUBBANDS_8			1
+
+#define SBC_ALLOCATION_SNR		(1 << 1)
+#define SBC_ALLOCATION_LOUDNESS		1
+
+#define MPEG_CHANNEL_MODE_MONO		(1 << 3)
+#define MPEG_CHANNEL_MODE_DUAL_CHANNEL	(1 << 2)
+#define MPEG_CHANNEL_MODE_STEREO	(1 << 1)
+#define MPEG_CHANNEL_MODE_JOINT_STEREO	1
+
+#define MPEG_LAYER_MP1			(1 << 2)
+#define MPEG_LAYER_MP2			(1 << 1)
+#define MPEG_LAYER_MP3			1
+
+#define MPEG_SAMPLING_FREQ_16000	(1 << 5)
+#define MPEG_SAMPLING_FREQ_22050	(1 << 4)
+#define MPEG_SAMPLING_FREQ_24000	(1 << 3)
+#define MPEG_SAMPLING_FREQ_32000	(1 << 2)
+#define MPEG_SAMPLING_FREQ_44100	(1 << 1)
+#define MPEG_SAMPLING_FREQ_48000	1
+
+#define MAX_BITPOOL 64
+#define MIN_BITPOOL 2
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+typedef struct {
+	uint8_t channel_mode:4;
+	uint8_t frequency:4;
+	uint8_t allocation_method:2;
+	uint8_t subbands:2;
+	uint8_t block_length:4;
+	uint8_t min_bitpool;
+	uint8_t max_bitpool;
+} __attribute__ ((packed)) a2dp_sbc_t;
+
+typedef struct {
+	uint8_t channel_mode:4;
+	uint8_t crc:1;
+	uint8_t layer:3;
+	uint8_t frequency:6;
+	uint8_t mpf:1;
+	uint8_t rfa:1;
+	uint16_t bitrate;
+} __attribute__ ((packed)) a2dp_mpeg_t;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+typedef struct {
+	uint8_t frequency:4;
+	uint8_t channel_mode:4;
+	uint8_t block_length:4;
+	uint8_t subbands:2;
+	uint8_t allocation_method:2;
+	uint8_t min_bitpool;
+	uint8_t max_bitpool;
+} __attribute__ ((packed)) a2dp_sbc_t;
+
+typedef struct {
+	uint8_t layer:3;
+	uint8_t crc:1;
+	uint8_t channel_mode:4;
+	uint8_t rfa:1;
+	uint8_t mpf:1;
+	uint8_t frequency:6;
+	uint16_t bitrate;
+} __attribute__ ((packed)) a2dp_mpeg_t;
+
+#else
+#error "Unknown byte order"
+#endif
diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index 5d388ce..740b317 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -29,6 +29,7 @@
 
 #include "bluetooth-util.h"
 #include "ipc.h"
+#include "a2dp-codecs.h"
 
 #define HFP_AG_ENDPOINT "/MediaEndpoint/HFPAG"
 #define A2DP_SOURCE_ENDPOINT "/MediaEndpoint/A2DPSource"
@@ -58,9 +59,6 @@
     " </interface>"                                                     \
     "</node>"
 
-#define MAX_BITPOOL 64
-#define MIN_BITPOOL 2U
-
 struct pa_bluetooth_discovery {
     PA_REFCNT_DECLARE;
 
@@ -636,7 +634,7 @@ static void register_endpoint(pa_bluetooth_discovery *y, const char *path, const
         uint8_t *caps = &capability;
         pa_dbus_append_basic_array_variant_dict_entry(&d, "Capabilities", DBUS_TYPE_BYTE, &caps, 1);
     } else {
-        sbc_capabilities_raw_t capabilities;
+        a2dp_sbc_t capabilities;
         uint8_t *caps = (uint8_t *) &capabilities;
 
         capabilities.channel_mode = BT_A2DP_CHANNEL_MODE_MONO | BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL |
@@ -1277,7 +1275,7 @@ static uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode) {
 
 static DBusMessage *endpoint_select_configuration(DBusConnection *c, DBusMessage *m, void *userdata) {
     pa_bluetooth_discovery *y = userdata;
-    sbc_capabilities_raw_t *cap, config;
+    a2dp_sbc_t *cap, config;
     uint8_t *pconf = (uint8_t *) &config;
     int i, size;
     DBusMessage *r;
diff --git a/src/modules/bluetooth/ipc.h b/src/modules/bluetooth/ipc.h
index 4547168..d69b97e 100644
--- a/src/modules/bluetooth/ipc.h
+++ b/src/modules/bluetooth/ipc.h
@@ -202,34 +202,6 @@ typedef struct {
 	uint8_t max_bitpool;
 } __attribute__ ((packed)) sbc_capabilities_t;
 
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-
-typedef struct {
-	uint8_t channel_mode:4;
-	uint8_t frequency:4;
-	uint8_t allocation_method:2;
-	uint8_t subbands:2;
-	uint8_t block_length:4;
-	uint8_t min_bitpool;
-	uint8_t max_bitpool;
-} __attribute__ ((packed)) sbc_capabilities_raw_t;
-
-#elif __BYTE_ORDER == __BIG_ENDIAN
-
-typedef struct {
-	uint8_t frequency:4;
-	uint8_t channel_mode:4;
-	uint8_t block_length:4;
-	uint8_t subbands:2;
-	uint8_t allocation_method:2;
-	uint8_t min_bitpool;
-	uint8_t max_bitpool;
-} __attribute__ ((packed)) sbc_capabilities_raw_t;
-
-#else
-#error "Unknown byte order"
-#endif
-
 typedef struct {
 	codec_capabilities_t capability;
 	uint8_t channel_mode;
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index ac0f16f..b132d42 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -52,12 +52,10 @@
 #include "module-bluetooth-device-symdef.h"
 #include "ipc.h"
 #include "sbc.h"
+#include "a2dp-codecs.h"
 #include "rtp.h"
 #include "bluetooth-util.h"
 
-#define MAX_BITPOOL 64
-#define MIN_BITPOOL 2U
-
 #define BITPOOL_DEC_LIMIT 32
 #define BITPOOL_DEC_STEP 5
 
@@ -2112,12 +2110,12 @@ static void shutdown_bt(struct userdata *u) {
 static int bt_transport_config_a2dp(struct userdata *u) {
     const pa_bluetooth_transport *t;
     struct a2dp_info *a2dp = &u->a2dp;
-    sbc_capabilities_raw_t *config;
+    a2dp_sbc_t *config;
 
     t = pa_bluetooth_discovery_get_transport(u->discovery, u->transport);
     pa_assert(t);
 
-    config = (sbc_capabilities_raw_t *) t->config;
+    config = (a2dp_sbc_t *) t->config;
 
     if (a2dp->sbc_initialized)
         sbc_reinit(&a2dp->sbc, 0);

commit 13d1928f3e0557d8809f67e1de77f07726267d23
Author: Sean McNamara <smcnam at gmail.com>
Date:   Wed Mar 30 13:41:02 2011 -0400

    vala: ChannelMap has no destroy function.

diff --git a/vala/libpulse.vapi b/vala/libpulse.vapi
index 4315988..06f412d 100644
--- a/vala/libpulse.vapi
+++ b/vala/libpulse.vapi
@@ -373,7 +373,7 @@ namespace PulseAudio {
                 public unowned CVolume? dec(Volume minus = 1);
         }
 
-        [CCode (cname="pa_channel_map")]
+        [CCode (cname="pa_channel_map",has_destroy_function=false)]
         public struct ChannelMap {
                 public uint8 channels;
                 public ChannelPosition map[];

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list