[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.13-401-gd5f46e8
Lennart Poettering
gitmailer-noreply at 0pointer.de
Mon Jan 26 20:04:07 PST 2009
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 afd817a0b607d732a7bfd2b31cef8a5b8cf9ab09 (commit)
- Log -----------------------------------------------------------------
d5f46e8... move flat volume logic into the core. while doing so add n_volume_steps field to sinks/sources
4bfa5d7... fix size calculation
eca3223... get rid of module-flat-volumes since we are moving this into the core
1be39e4... allow samples to be played with 'default' (i.e. unspecified) volume.
5449d79... swap argument order of pa_cvolume_get_balance() to be a bit more systematic
df8ad5d... add a few missing doxygen comments
6058530... import version.h in all header files to make sure that version-based feature testing works
1249cf6... always define PA_MAJOR/PA_MINOR/PA_MICRO to ease feature checking in client applications
948be36... invert an ill-placed assert
0658d9a... show pretty channel map name if possible
07db64b... remove redundant cast
9ba4084... store requested resampling method in a seperate field and use it when create a new resampler after a move
ccd21f3... make a few comments appear in doxygen
3bcbe1d... check for availability of RLIMIT_NOFILE and RLIMIT_AS before we make use of it
4e31e00... implement pa_cvolume_scale()
e52c5ea... implement new API functions pa_channel_map_can_balance(), pa_channel_map_to_name() and pa_channel_map_to_pretty_name()
24b3a74... add a bitset implementation
-----------------------------------------------------------------------
Summary of changes:
configure.ac | 15 +-
man/pulse-daemon.conf.5.xml.in | 9 +-
src/Makefile.am | 11 +-
src/daemon/daemon-conf.c | 24 ++-
src/daemon/daemon-conf.h | 12 +-
src/daemon/daemon.conf.in | 2 +
src/daemon/default.pa.in | 3 -
src/daemon/main.c | 3 +
src/map-file | 4 +
src/modules/alsa/alsa-sink.c | 43 ++---
src/modules/alsa/alsa-source.c | 43 ++---
src/modules/bluetooth/module-bluetooth-device.c | 2 +-
src/modules/module-flat-volume.c | 224 --------------------
src/modules/module-lirc.c | 4 +-
src/modules/module-mmkbd-evdev.c | 4 +-
src/modules/module-position-event-sounds.c | 16 +-
src/modules/module-raop-sink.c | 32 +--
src/modules/module-stream-restore.c | 4 +-
src/modules/module-tunnel.c | 16 +-
src/modules/module-volume-restore.c | 2 +-
src/modules/oss/module-oss.c | 62 +++----
src/pulse/browser.h | 1 +
src/pulse/channelmap.c | 187 ++++++++++++++++-
src/pulse/channelmap.h | 22 ++-
src/pulse/context.h | 5 +-
src/pulse/def.h | 8 +-
src/pulse/error.h | 1 +
src/pulse/ext-stream-restore.h | 1 +
src/pulse/gccmacro.h | 4 +
src/pulse/glib-mainloop.h | 1 +
src/pulse/i18n.h | 1 +
src/pulse/introspect.c | 8 +-
src/pulse/introspect.h | 7 +-
src/pulse/mainloop-api.h | 1 +
src/pulse/mainloop-signal.h | 2 +
src/pulse/operation.h | 1 +
src/pulse/proplist.h | 3 +-
src/pulse/sample.h | 1 +
src/pulse/scache.c | 8 +
src/pulse/scache.h | 5 +-
src/pulse/simple.h | 1 +
src/pulse/subscribe.h | 1 +
src/pulse/thread-mainloop.h | 1 +
src/pulse/timeval.h | 12 +
src/pulse/utf8.h | 1 +
src/pulse/util.h | 1 +
src/pulse/version.h.in | 9 +
src/pulse/volume.c | 23 ++-
src/pulse/volume.h | 12 +-
src/pulse/xmalloc.h | 1 +
src/pulsecore/{semaphore-win32.c => bitset.c} | 58 +++---
src/pulsecore/{sioman.c => bitset.h} | 26 +--
src/pulsecore/cli-command.c | 2 +-
src/pulsecore/cli-text.c | 54 ++++-
src/pulsecore/core-scache.c | 30 ++-
src/pulsecore/core-scache.h | 1 +
src/pulsecore/core.c | 1 +
src/pulsecore/core.h | 2 +-
src/pulsecore/play-memblockq.c | 2 +-
src/pulsecore/protocol-native.c | 15 +-
src/pulsecore/sink-input.c | 167 ++++++++++-----
src/pulsecore/sink-input.h | 46 ++---
src/pulsecore/sink.c | 257 +++++++++++++++++------
src/pulsecore/sink.h | 41 ++--
src/pulsecore/sound-file-stream.c | 2 +-
src/pulsecore/source-output.c | 21 +-
src/pulsecore/source-output.h | 4 +-
src/pulsecore/source.c | 85 ++++----
src/pulsecore/source.h | 27 ++-
src/tests/voltest.c | 8 +-
src/utils/pactl.c | 8 +-
71 files changed, 1023 insertions(+), 698 deletions(-)
delete mode 100644 src/modules/module-flat-volume.c
copy src/pulsecore/{semaphore-win32.c => bitset.c} (51%)
copy src/pulsecore/{sioman.c => bitset.h} (64%)
-----------------------------------------------------------------------
commit 24b3a743bd8a18741b2c1e0370f18afb90ed1ea5
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 00:44:45 2009 +0100
add a bitset implementation
diff --git a/src/Makefile.am b/src/Makefile.am
index d82d8a6..f313bb5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -556,6 +556,7 @@ libpulsecommon_ at PA_MAJORMINORMICRO@_la_SOURCES = \
pulsecore/refcnt.h \
pulsecore/rtclock.c pulsecore/rtclock.h \
pulsecore/shm.c pulsecore/shm.h \
+ pulsecore/bitset.c pulsecore/bitset.h \
pulsecore/socket-client.c pulsecore/socket-client.h \
pulsecore/socket-server.c pulsecore/socket-server.h \
pulsecore/socket-util.c pulsecore/socket-util.h \
diff --git a/src/pulsecore/bitset.c b/src/pulsecore/bitset.c
new file mode 100644
index 0000000..4beeb1c
--- /dev/null
+++ b/src/pulsecore/bitset.c
@@ -0,0 +1,67 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2009 Lennart Poettering
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <pulse/xmalloc.h>
+
+#include "bitset.h"
+
+void pa_bitset_set(pa_bitset_t *b, unsigned k, pa_bool_t v) {
+ pa_assert(b);
+
+ if (v)
+ b[k >> 5] |= 1 << (k & 31);
+ else
+ b[k >> 5] &= ~((uint32_t) (1 << (k & 31)));
+}
+
+pa_bool_t pa_bitset_get(const pa_bitset_t *b, unsigned k) {
+ return !!(b[k >> 5] & (1 << (k & 31)));
+}
+
+pa_bool_t pa_bitset_equals(const pa_bitset_t *b, unsigned n, ...) {
+ va_list ap;
+ pa_bitset_t *a;
+ pa_bool_t equal;
+
+ a = pa_xnew0(pa_bitset_t, PA_BITSET_ELEMENTS(n));
+
+ va_start(ap, n);
+ for (;;) {
+ int j = va_arg(ap, int);
+
+ if (j < 0)
+ break;
+
+ pa_bitset_set(a, j, TRUE);
+ }
+ va_end(ap);
+
+ equal = memcmp(a, b, PA_BITSET_SIZE(n)) == 0;
+ pa_xfree(a);
+
+ return equal;
+}
diff --git a/src/pulsecore/bitset.h b/src/pulsecore/bitset.h
new file mode 100644
index 0000000..21e840a
--- /dev/null
+++ b/src/pulsecore/bitset.h
@@ -0,0 +1,37 @@
+#ifndef foopulsecorebitsethfoo
+#define foopulsecorebitsethfoo
+
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2009 Lennart Poettering
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#include <inttypes.h>
+#include <pulsecore/macro.h>
+
+#define PA_BITSET_ELEMENTS(n) (((n)+31)/32)
+#define PA_BITSET_SIZE(n) (PA_BITSET_ELEMENTS(n)*32)
+
+typedef uint32_t pa_bitset_t;
+
+void pa_bitset_set(pa_bitset_t *b, unsigned k, pa_bool_t v);
+pa_bool_t pa_bitset_get(const pa_bitset_t *b, unsigned k);
+pa_bool_t pa_bitset_equals(const pa_bitset_t *b, unsigned n, ...);
+
+#endif
commit e52c5ea68a9c3bf6e7c4b30cb6c2d4706f214cd3
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 00:46:39 2009 +0100
implement new API functions pa_channel_map_can_balance(), pa_channel_map_to_name() and pa_channel_map_to_pretty_name()
diff --git a/src/map-file b/src/map-file
index 55b13e1..cb5c749 100644
--- a/src/map-file
+++ b/src/map-file
@@ -9,6 +9,7 @@ pa_browser_unref;
pa_bytes_per_second;
pa_bytes_snprint;
pa_bytes_to_usec;
+pa_channel_map_can_balance;
pa_channel_map_compatible;
pa_channel_map_equal;
pa_channel_map_init;
@@ -19,6 +20,8 @@ pa_channel_map_init_stereo;
pa_channel_map_parse;
pa_channel_map_snprint;
pa_channel_map_superset;
+pa_channel_map_to_name;
+pa_channel_map_to_pretty_name;
pa_channel_map_valid;
pa_channel_position_to_pretty_string;
pa_channel_position_to_string;
diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c
index 26eae59..455bda1 100644
--- a/src/pulse/channelmap.c
+++ b/src/pulse/channelmap.c
@@ -32,6 +32,7 @@
#include <pulse/i18n.h>
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
+#include <pulsecore/bitset.h>
#include "channelmap.h"
@@ -497,11 +498,58 @@ pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
pa_channel_map_init(&map);
+ /* We don't need to match against the well known channel mapping
+ * "mono" here explicitly, because that can be understood as
+ * listing with one channel called "mono". */
+
if (strcmp(s, "stereo") == 0) {
map.channels = 2;
map.map[0] = PA_CHANNEL_POSITION_LEFT;
map.map[1] = PA_CHANNEL_POSITION_RIGHT;
goto finish;
+ } else if (strcmp(s, "surround-40") == 0) {
+ map.channels = 4;
+ map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
+ map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
+ map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
+ map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
+ goto finish;
+ } else if (strcmp(s, "surround-41") == 0) {
+ map.channels = 5;
+ map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
+ map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
+ map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
+ map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
+ map.map[4] = PA_CHANNEL_POSITION_LFE;
+ goto finish;
+ } else if (strcmp(s, "surround-50") == 0) {
+ map.channels = 5;
+ map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
+ map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
+ map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
+ map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
+ map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
+ goto finish;
+ } else if (strcmp(s, "surround-51") == 0) {
+ map.channels = 6;
+ map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
+ map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
+ map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
+ map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
+ map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
+ map.map[5] = PA_CHANNEL_POSITION_LFE;
+ goto finish;
+ } else if (strcmp(s, "surround-71") == 0) {
+ map.channels = 8;
+ map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
+ map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
+ map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
+ map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
+ map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
+ map.map[5] = PA_CHANNEL_POSITION_LFE;
+ map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
+ map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
+ goto finish;
}
state = NULL;
@@ -579,7 +627,7 @@ int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *s
}
int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
- pa_bool_t in_a[PA_CHANNEL_POSITION_MAX];
+ pa_bitset_t in_a[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
unsigned i;
pa_assert(a);
@@ -588,11 +636,144 @@ int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
memset(in_a, 0, sizeof(in_a));
for (i = 0; i < a->channels; i++)
- in_a[a->map[i]] = TRUE;
+ pa_bitset_set(in_a, a->map[i], TRUE);
for (i = 0; i < b->channels; i++)
- if (!in_a[b->map[i]])
+ if (!pa_bitset_get(in_a, b->map[i]))
return 0;
return 1;
}
+
+int pa_channel_map_can_balance(const pa_channel_map *map) {
+ unsigned c;
+
+ pa_assert(map);
+
+ for (c = 0; c < map->channels; c++)
+
+ switch (map->map[c]) {
+ case PA_CHANNEL_POSITION_LEFT:
+ case PA_CHANNEL_POSITION_RIGHT:
+ case PA_CHANNEL_POSITION_REAR_LEFT:
+ case PA_CHANNEL_POSITION_REAR_RIGHT:
+ case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
+ case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
+ case PA_CHANNEL_POSITION_SIDE_LEFT:
+ case PA_CHANNEL_POSITION_SIDE_RIGHT:
+ case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
+ case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
+ case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
+ case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
+ return 1;
+
+ default:
+ ;
+ }
+
+ return 0;
+}
+
+const char* pa_channel_map_to_name(const pa_channel_map *map) {
+ pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
+ unsigned c;
+
+ pa_assert(map);
+
+ memset(in_map, 0, sizeof(in_map));
+
+ for (c = 0; c < map->channels; c++)
+ pa_bitset_set(in_map, map->map[c], TRUE);
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_MONO, -1))
+ return "mono";
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
+ return "stereo";
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
+ return "surround-40";
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
+ PA_CHANNEL_POSITION_LFE, -1))
+ return "surround-41";
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
+ PA_CHANNEL_POSITION_FRONT_CENTER, -1))
+ return "surround-50";
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
+ PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
+ return "surround-51";
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
+ PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
+ PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
+ return "surround-71";
+
+ return NULL;
+}
+
+const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) {
+ pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
+ unsigned c;
+
+ pa_assert(map);
+
+ memset(in_map, 0, sizeof(in_map));
+
+ for (c = 0; c < map->channels; c++)
+ pa_bitset_set(in_map, map->map[c], TRUE);
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_MONO, -1))
+ return _("Mono");
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
+ return _("Stereo");
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
+ return _("Surround 4.0");
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
+ PA_CHANNEL_POSITION_LFE, -1))
+ return _("Surround 4.1");
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
+ PA_CHANNEL_POSITION_FRONT_CENTER, -1))
+ return _("Surround 5.0");
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
+ PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
+ return _("Surround 5.1");
+
+ if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
+ PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
+ PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
+ return _("Surround 7.1");
+
+ return NULL;
+}
diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h
index a6c044f..6e92e76 100644
--- a/src/pulse/channelmap.h
+++ b/src/pulse/channelmap.h
@@ -214,7 +214,10 @@ const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos);
/** Make a humand readable string from the specified channel map */
char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map);
-/** Parse a channel position list into a channel map structure. */
+/** Parse a channel position list or well-known mapping name into a
+ * channel map structure. This turns the output of
+ * pa_channel_map_snprint() and pa_channel_map_to_name() back into a
+ * pa_channel_map */
pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s);
/** Compare two channel maps. Return 1 if both match. */
@@ -230,6 +233,22 @@ int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *s
/** Returns non-zero if every channel defined in b is also defined in a. \since 0.9.15 */
int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) PA_GCC_PURE;
+/** Returns non-zero if it makes sense to apply a volume 'balance'
+ * with this mapping, i.e. if there are left/right channels
+ * available. \since 0.9.15 */
+int pa_channel_map_can_balance(const pa_channel_map *map) PA_GCC_PURE;
+
+/** Tries to find a well-known channel mapping name for this channel
+ * mapping. I.e. "stereo", "surround-71" and so on. If the channel
+ * mapping is unknown NULL will be returned. This name can be parsed
+ * with pa_channel_map_parse() \since 0.9.15 */
+const char* pa_channel_map_to_name(const pa_channel_map *map) PA_GCC_PURE;
+
+/** Tries to find a human readable text label for this channel
+mapping. I.e. "Stereo", "Surround 7.1" and so on. If the channel
+mapping is unknown NULL will be returned. \since 0.9.15 */
+const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) PA_GCC_PURE;
+
PA_C_DECL_END
#endif
commit 4e31e00b63117f36df6b8ed4850e7ad6264e3da7
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 00:47:07 2009 +0100
implement pa_cvolume_scale()
diff --git a/src/map-file b/src/map-file
index cb5c749..d613759 100644
--- a/src/map-file
+++ b/src/map-file
@@ -113,6 +113,7 @@ pa_cvolume_get_balance;
pa_cvolume_init;
pa_cvolume_max;
pa_cvolume_remap;
+pa_cvolume_scale;
pa_cvolume_set;
pa_cvolume_set_balance;
pa_cvolume_snprint;
diff --git a/src/pulse/volume.c b/src/pulse/volume.c
index 10a44da..2c97784 100644
--- a/src/pulse/volume.c
+++ b/src/pulse/volume.c
@@ -500,3 +500,22 @@ pa_cvolume* pa_cvolume_set_balance(const pa_channel_map *map, pa_cvolume *v, flo
return v;
}
+
+pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) {
+ unsigned c;
+ pa_volume_t t = 0;
+
+ pa_assert(c);
+
+ for (c = 0; c < v->channels; c++)
+ if (v->values[c] > t)
+ t = v->values[c];
+
+ if (t <= 0)
+ return pa_cvolume_set(v, v->channels, max);
+
+ for (c = 0; c < v->channels; c++)
+ v->values[c] = (pa_volume_t) (((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
+
+ return v;
+}
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index 38da5df..c8b73f4 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -244,9 +244,14 @@ float pa_cvolume_get_balance(const pa_channel_map *map, const pa_cvolume *v) PA_
* operation might not be reversable! Also, after this call
* pa_cvolume_get_balance() is not guaranteed to actually return the
* requested balance (e.g. when the input volume was zero anyway for
- * all channels)- \since 0.9.15 */
+ * all channels) \since 0.9.15 */
pa_cvolume* pa_cvolume_set_balance(const pa_channel_map *map, pa_cvolume *v, float new_balance);
+/** Scale the passed pa_cvolume structure so that the maximum volume
+ * of all channels equals max. The proportions between the channel
+ * volumes are kept. \since 0.9.15 */
+pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max);
+
PA_C_DECL_END
#endif
commit 3bcbe1d18f08667ca7b9d690e5c211c25831e0ad
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 00:48:53 2009 +0100
check for availability of RLIMIT_NOFILE and RLIMIT_AS before we make use of it
diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index c3abc09..c8c1b6f 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -97,11 +97,15 @@ static const pa_daemon_conf default_conf = {
#ifdef RLIMIT_NPROC
,.rlimit_nproc = { .value = 0, .is_set = FALSE }
#endif
+#ifdef RLIMIT_NOFILE
,.rlimit_nofile = { .value = 256, .is_set = TRUE }
+#endif
#ifdef RLIMIT_MEMLOCK
,.rlimit_memlock = { .value = 0, .is_set = FALSE }
#endif
+#ifdef RLIMIT_AS
,.rlimit_as = { .value = 0, .is_set = FALSE }
+#endif
#ifdef RLIMIT_LOCKS
,.rlimit_locks = { .value = 0, .is_set = FALSE }
#endif
@@ -442,8 +446,12 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
{ "rlimit-stack", parse_rlimit, NULL },
{ "rlimit-core", parse_rlimit, NULL },
{ "rlimit-rss", parse_rlimit, NULL },
+#ifdef RLIMIT_NOFILE
{ "rlimit-nofile", parse_rlimit, NULL },
+#endif
+#ifdef RLIMIT_AS
{ "rlimit-as", parse_rlimit, NULL },
+#endif
#ifdef RLIMIT_NPROC
{ "rlimit-nproc", parse_rlimit, NULL },
#endif
@@ -508,10 +516,14 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
table[i++].data = &c->rlimit_fsize;
table[i++].data = &c->rlimit_data;
table[i++].data = &c->rlimit_stack;
- table[i++].data = &c->rlimit_as;
table[i++].data = &c->rlimit_core;
+ table[i++].data = &c->rlimit_rss;
+#ifdef RLIMIT_NOFILE
table[i++].data = &c->rlimit_nofile;
+#endif
+#ifdef RLIMIT_AS
table[i++].data = &c->rlimit_as;
+#endif
#ifdef RLIMIT_NPROC
table[i++].data = &c->rlimit_nproc;
#endif
@@ -662,12 +674,16 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
pa_strbuf_printf(s, "rlimit-data = %li\n", c->rlimit_data.is_set ? (long int) c->rlimit_data.value : -1);
pa_strbuf_printf(s, "rlimit-stack = %li\n", c->rlimit_stack.is_set ? (long int) c->rlimit_stack.value : -1);
pa_strbuf_printf(s, "rlimit-core = %li\n", c->rlimit_core.is_set ? (long int) c->rlimit_core.value : -1);
- pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1);
pa_strbuf_printf(s, "rlimit-rss = %li\n", c->rlimit_rss.is_set ? (long int) c->rlimit_rss.value : -1);
+#ifdef RLIMIT_AS
+ pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1);
+#endif
#ifdef RLIMIT_NPROC
pa_strbuf_printf(s, "rlimit-nproc = %li\n", c->rlimit_nproc.is_set ? (long int) c->rlimit_nproc.value : -1);
#endif
+#ifdef RLIMIT_NOFILE
pa_strbuf_printf(s, "rlimit-nofile = %li\n", c->rlimit_nofile.is_set ? (long int) c->rlimit_nofile.value : -1);
+#endif
#ifdef RLIMIT_MEMLOCK
pa_strbuf_printf(s, "rlimit-memlock = %li\n", c->rlimit_memlock.is_set ? (long int) c->rlimit_memlock.value : -1);
#endif
diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h
index fffa35e..3b75b83 100644
--- a/src/daemon/daemon-conf.h
+++ b/src/daemon/daemon-conf.h
@@ -84,7 +84,14 @@ typedef struct pa_daemon_conf {
char *config_file;
#ifdef HAVE_SYS_RESOURCE_H
- pa_rlimit rlimit_fsize, rlimit_data, rlimit_stack, rlimit_core, rlimit_rss, rlimit_nofile, rlimit_as;
+ pa_rlimit rlimit_fsize, rlimit_data, rlimit_stack, rlimit_core, rlimit_rss;
+
+#ifdef RLIMIT_NOFILE
+ pa_rlimit rlimit_nofile;
+#endif
+#ifdef RLIMIT_AS
+ pa_rlimit rlimit_as;
+#endif
#ifdef RLIMIT_NPROC
pa_rlimit rlimit_nproc;
#endif
diff --git a/src/daemon/main.c b/src/daemon/main.c
index f483607..9705f4c 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -298,7 +298,9 @@ static void set_all_rlimits(const pa_daemon_conf *conf) {
#ifdef RLIMIT_NPROC
set_one_rlimit(&conf->rlimit_nproc, RLIMIT_NPROC, "RLIMIT_NPROC");
#endif
+#ifdef RLIMIT_NOFILE
set_one_rlimit(&conf->rlimit_nofile, RLIMIT_NOFILE, "RLIMIT_NOFILE");
+#endif
#ifdef RLIMIT_MEMLOCK
set_one_rlimit(&conf->rlimit_memlock, RLIMIT_MEMLOCK, "RLIMIT_MEMLOCK");
#endif
commit ccd21f33cf254cad6348769b42646fe8b0c5d0a5
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 00:49:58 2009 +0100
make a few comments appear in doxygen
diff --git a/src/pulse/context.h b/src/pulse/context.h
index 3b51397..fd791b9 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -232,14 +232,14 @@ uint32_t pa_context_get_protocol_version(pa_context *c);
/** Return the protocol version of the connected server. */
uint32_t pa_context_get_server_protocol_version(pa_context *c);
-/* Update the property list of the client, adding new entries. Please
+/** Update the property list of the client, adding new entries. Please
* note that it is highly recommended to set as much properties
* initially via pa_context_new_with_proplist() as possible instead a
* posteriori with this function, since that information may then be
* used to route streams of the client to the right device. \since 0.9.11 */
pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, pa_proplist *p, pa_context_success_cb_t cb, void *userdata);
-/* Update the property list of the client, remove entries. \since 0.9.11 */
+/** Update the property list of the client, remove entries. \since 0.9.11 */
pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata);
/** Return the client index this context is
commit 9ba408415c28c1113291062b4dbb38cf90a3c232
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 00:52:28 2009 +0100
store requested resampling method in a seperate field and use it when create a new resampler after a move
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index e25e0c2..a33d62f 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -218,8 +218,6 @@ pa_sink_input* pa_sink_input_new(
pa_log_warn("Unsupported resampling operation.");
return NULL;
}
-
- data->resample_method = pa_resampler_get_method(resampler);
}
i = pa_msgobject_new(pa_sink_input);
@@ -235,7 +233,8 @@ pa_sink_input* pa_sink_input_new(
i->sink = data->sink;
i->client = data->client;
- i->resample_method = data->resample_method;
+ i->requested_resample_method = data->resample_method;
+ i->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID;
i->sample_spec = data->sample_spec;
i->channel_map = data->channel_map;
@@ -946,7 +945,7 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
pa_sink_input_assert_ref(i);
- return i->resample_method;
+ return i->actual_resample_method;
}
/* Called from main context */
@@ -1062,7 +1061,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest) {
i->core->mempool,
&i->sample_spec, &i->channel_map,
&dest->sample_spec, &dest->channel_map,
- i->resample_method,
+ i->requested_resample_method,
((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
((i->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
(i->core->disable_remixing || (i->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index a533046..66ec613 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -95,7 +95,7 @@ struct pa_sink_input {
pa_cvolume volume;
pa_bool_t muted;
- pa_resample_method_t resample_method;
+ pa_resample_method_t requested_resample_method, actual_resample_method;
/* Returns the chunk of audio data and drops it from the
* queue. Returns -1 on failure. Called from IO thread context. If
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index d4f0367..1d21ffb 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -181,8 +181,6 @@ pa_source_output* pa_source_output_new(
pa_log_warn("Unsupported resampling operation.");
return NULL;
}
-
- data->resample_method = pa_resampler_get_method(resampler);
}
o = pa_msgobject_new(pa_source_output);
@@ -198,7 +196,9 @@ pa_source_output* pa_source_output_new(
o->source = data->source;
o->client = data->client;
- o->resample_method = data->resample_method;
+
+ o->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID;
+ o->requested_resample_method = data->resample_method;
o->sample_spec = data->sample_spec;
o->channel_map = data->channel_map;
@@ -628,7 +628,7 @@ pa_bool_t pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t
pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
pa_source_output_assert_ref(o);
- return o->resample_method;
+ return o->actual_resample_method;
}
/* Called from main context */
@@ -730,7 +730,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest) {
o->core->mempool,
&dest->sample_spec, &dest->channel_map,
&o->sample_spec, &o->channel_map,
- o->resample_method,
+ o->requested_resample_method,
((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
(o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index a27602e..d60e425 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -79,7 +79,7 @@ struct pa_source_output {
pa_sample_spec sample_spec;
pa_channel_map channel_map;
- pa_resample_method_t resample_method;
+ pa_resample_method_t requested_resample_method, actual_resample_method;
/* Pushes a new memchunk into the output. Called from IO thread
* context. */
@@ -139,7 +139,7 @@ struct pa_source_output {
struct {
pa_source_output_state_t state;
- pa_bool_t attached; /* True only between ->attach() and ->detach() calls */
+ pa_bool_t attached:1; /* True only between ->attach() and ->detach() calls */
pa_sample_spec sample_spec;
commit 07db64b9d31cb2d7315200058e4b3680b88db408
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 00:53:31 2009 +0100
remove redundant cast
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index b22578e..804be35 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -600,7 +600,7 @@ static int sco_process_render(struct userdata *u) {
for (;;) {
ssize_t l;
- l = pa_loop_write(u->stream_fd, (uint8_t*) p, memchunk.length, NULL);
+ l = pa_loop_write(u->stream_fd, p, memchunk.length, NULL);
pa_log_debug("Memblock written to socket: %li bytes", (long) l);
pa_assert(l != 0);
commit 0658d9ae929d4d2f79c5cdbc650745cafc3f8217
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 00:55:35 2009 +0100
show pretty channel map name if possible
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 1a3778a..7f3a745 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -221,6 +221,9 @@ char *pa_sink_list_to_string(pa_core *c) {
vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t;
pa_usec_t min_latency, max_latency;
+ const char *cmn;
+
+ cmn = pa_channel_map_to_pretty_name(&sink->channel_map);
pa_sink_get_latency_range(sink, &min_latency, &max_latency);
@@ -241,7 +244,7 @@ char *pa_sink_list_to_string(pa_core *c) {
"\tmax rewind: %lu KiB\n"
"\tmonitor source: %u\n"
"\tsample spec: %s\n"
- "\tchannel map: %s\n"
+ "\tchannel map: %s%s%s\n"
"\tused by: %u\n"
"\tlinked by: %u\n",
c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ',
@@ -272,6 +275,8 @@ char *pa_sink_list_to_string(pa_core *c) {
sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map),
+ cmn ? "\n\t " : "",
+ cmn ? cmn : "",
pa_sink_used_by(sink),
pa_sink_linked_by(sink));
@@ -306,6 +311,9 @@ char *pa_source_list_to_string(pa_core *c) {
vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t;
pa_usec_t min_latency, max_latency;
+ const char *cmn;
+
+ cmn = pa_channel_map_to_pretty_name(&source->channel_map);
pa_source_get_latency_range(source, &min_latency, &max_latency);
@@ -324,7 +332,7 @@ char *pa_source_list_to_string(pa_core *c) {
"\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n"
"\tmax rewind: %lu KiB\n"
"\tsample spec: %s\n"
- "\tchannel map: %s\n"
+ "\tchannel map: %s%s%s\n"
"\tused by: %u\n"
"\tlinked by: %u\n",
c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ',
@@ -353,6 +361,8 @@ char *pa_source_list_to_string(pa_core *c) {
(unsigned long) pa_source_get_max_rewind(source) / 1024,
pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map),
+ cmn ? "\n\t " : "",
+ cmn ? cmn : "",
pa_source_used_by(source),
pa_source_linked_by(source));
@@ -391,6 +401,9 @@ char *pa_source_output_list_to_string(pa_core *c) {
for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) {
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t, clt[28];
pa_usec_t cl;
+ const char *cmn;
+
+ cmn = pa_channel_map_to_pretty_name(&o->channel_map);
if ((cl = pa_source_output_get_requested_latency(o)) == (pa_usec_t) -1)
pa_snprintf(clt, sizeof(clt), "n/a");
@@ -409,7 +422,7 @@ char *pa_source_output_list_to_string(pa_core *c) {
"\tcurrent latency: %0.2f ms\n"
"\trequested latency: %s\n"
"\tsample spec: %s\n"
- "\tchannel map: %s\n"
+ "\tchannel map: %s%s%s\n"
"\tresample method: %s\n",
o->index,
o->driver,
@@ -427,6 +440,8 @@ char *pa_source_output_list_to_string(pa_core *c) {
clt,
pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map),
+ cmn ? "\n\t " : "",
+ cmn ? cmn : "",
pa_resample_method_to_string(pa_source_output_get_resample_method(o)));
if (o->module)
pa_strbuf_printf(s, "\towner module: %u\n", o->module->index);
@@ -463,6 +478,9 @@ char *pa_sink_input_list_to_string(pa_core *c) {
for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) {
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t, clt[28];
pa_usec_t cl;
+ const char *cmn;
+
+ cmn = pa_channel_map_to_pretty_name(&i->channel_map);
if ((cl = pa_sink_input_get_requested_latency(i)) == (pa_usec_t) -1)
pa_snprintf(clt, sizeof(clt), "n/a");
@@ -485,7 +503,7 @@ char *pa_sink_input_list_to_string(pa_core *c) {
"\tcurrent latency: %0.2f ms\n"
"\trequested latency: %s\n"
"\tsample spec: %s\n"
- "\tchannel map: %s\n"
+ "\tchannel map: %s%s%s\n"
"\tresample method: %s\n",
i->index,
i->driver,
@@ -507,6 +525,8 @@ char *pa_sink_input_list_to_string(pa_core *c) {
clt,
pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
+ cmn ? "\n\t " : "",
+ cmn ? cmn : "",
pa_resample_method_to_string(pa_sink_input_get_resample_method(i)));
if (i->module)
@@ -537,6 +557,9 @@ char *pa_scache_list_to_string(pa_core *c) {
for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) {
double l = 0;
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX] = "n/a", *t;
+ const char *cmn;
+
+ cmn = pa_channel_map_to_pretty_name(&e->channel_map);
if (e->memchunk.memblock) {
pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec);
@@ -549,7 +572,7 @@ char *pa_scache_list_to_string(pa_core *c) {
" name: <%s>\n"
"\tindex: %u\n"
"\tsample spec: %s\n"
- "\tchannel map: %s\n"
+ "\tchannel map: %s%s%s\n"
"\tlength: %lu\n"
"\tduration: %0.1f s\n"
"\tvolume: %s\n"
@@ -561,6 +584,8 @@ char *pa_scache_list_to_string(pa_core *c) {
e->index,
ss,
cm,
+ cmn ? "\n\t " : "",
+ cmn ? cmn : "",
(long unsigned)(e->memchunk.memblock ? e->memchunk.length : 0),
l,
pa_cvolume_snprint(cv, sizeof(cv), &e->volume),
commit 948be361c44f16f9982a92d33259625b7256dd3e
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 00:56:57 2009 +0100
invert an ill-placed assert
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index a33d62f..d1ffb0f 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -1110,7 +1110,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest) {
int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) {
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
- pa_assert(!i->sink);
+ pa_assert(i->sink);
pa_sink_assert_ref(dest);
if (dest == i->sink)
commit 1249cf6dc9032810575fc5b94c002bf633316bfb
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 02:16:20 2009 +0100
always define PA_MAJOR/PA_MINOR/PA_MICRO to ease feature checking in client applications
diff --git a/configure.ac b/configure.ac
index 34ce25a..c02b20e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -22,18 +22,21 @@
AC_PREREQ(2.63)
-m4_define(PA_MAJOR, [0])
-m4_define(PA_MINOR, [9])
-m4_define(PA_MICRO, [15])
+m4_define(pa_major, [0])
+m4_define(pa_minor, [9])
+m4_define(pa_micro, [15])
-AC_INIT([pulseaudio],[PA_MAJOR.PA_MINOR.PA_MICRO],[mzchyfrnhqvb (at) 0pointer (dot) net])
+AC_INIT([pulseaudio],[pa_major.pa_minor.pa_micro],[mzchyfrnhqvb (at) 0pointer (dot) net])
AC_CONFIG_SRCDIR([src/daemon/main.c])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([foreign 1.10 -Wall])
-AC_SUBST(PA_MAJORMINOR, PA_MAJOR.PA_MINOR)
-AC_SUBST(PA_MAJORMINORMICRO, PA_MAJOR.PA_MINOR.PA_MICRO)
+AC_SUBST(PA_MAJOR, pa_major)
+AC_SUBST(PA_MINOR, pa_minor)
+AC_SUBST(PA_MICRO, pa_micro)
+AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
+AC_SUBST(PA_MAJORMINORMICRO, pa_major.pa_minor.pa_micro)
AC_SUBST(PACKAGE_URL, [http://pulseaudio.org/])
AC_SUBST(PA_API_VERSION, 12)
diff --git a/src/pulse/version.h.in b/src/pulse/version.h.in
index 0e37f98..566dd55 100644
--- a/src/pulse/version.h.in
+++ b/src/pulse/version.h.in
@@ -51,6 +51,15 @@ const char* pa_get_library_version(void);
* 0.8/PulseAudio 0.9. */
#define PA_PROTOCOL_VERSION @PA_PROTOCOL_VERSION@
+/** The major version of PA. \since 0.9.15 */
+#define PA_MAJOR @PA_MAJOR@
+
+/** The minor version of PA. \since 0.9.15 */
+#define PA_MINOR @PA_MINOR@
+
+/** The micro version of PA. \since 0.9.15 */
+#define PA_MICRO @PA_MICRO@
+
PA_C_DECL_END
#endif
commit 605853057114892c8e6b2e1ef1b5f745d36f88a4
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 02:36:42 2009 +0100
import version.h in all header files to make sure that version-based feature testing works
diff --git a/src/pulse/browser.h b/src/pulse/browser.h
index c4e0a17..499fae2 100644
--- a/src/pulse/browser.h
+++ b/src/pulse/browser.h
@@ -26,6 +26,7 @@
#include <pulse/sample.h>
#include <pulse/channelmap.h>
#include <pulse/cdecl.h>
+#include <pulse/version.h>
/** \file
* An abstract interface for Zeroconf browsing of PulseAudio servers */
diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h
index 6e92e76..de2d712 100644
--- a/src/pulse/channelmap.h
+++ b/src/pulse/channelmap.h
@@ -26,6 +26,7 @@
#include <pulse/sample.h>
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
+#include <pulse/version.h>
/** \page channelmap Channel Maps
*
diff --git a/src/pulse/context.h b/src/pulse/context.h
index fd791b9..dfb7e4a 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -29,6 +29,7 @@
#include <pulse/cdecl.h>
#include <pulse/operation.h>
#include <pulse/proplist.h>
+#include <pulse/version.h>
/** \page async Asynchronous API
*
diff --git a/src/pulse/def.h b/src/pulse/def.h
index be5cc23..c2c90e9 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -29,6 +29,7 @@
#include <pulse/cdecl.h>
#include <pulse/sample.h>
+#include <pulse/version.h>
/** \file
* Global definitions */
diff --git a/src/pulse/error.h b/src/pulse/error.h
index 9f9e3d3..c30b80b 100644
--- a/src/pulse/error.h
+++ b/src/pulse/error.h
@@ -25,6 +25,7 @@
#include <inttypes.h>
#include <pulse/cdecl.h>
+#include <pulse/version.h>
/** \file
* Error management */
diff --git a/src/pulse/ext-stream-restore.h b/src/pulse/ext-stream-restore.h
index 2038eb4..ac01d23 100644
--- a/src/pulse/ext-stream-restore.h
+++ b/src/pulse/ext-stream-restore.h
@@ -23,6 +23,7 @@
***/
#include <pulse/context.h>
+#include <pulse/version.h>
/** \file
*
diff --git a/src/pulse/glib-mainloop.h b/src/pulse/glib-mainloop.h
index 60fd61a..fd68f8a 100644
--- a/src/pulse/glib-mainloop.h
+++ b/src/pulse/glib-mainloop.h
@@ -27,6 +27,7 @@
#include <pulse/mainloop-api.h>
#include <pulse/cdecl.h>
+#include <pulse/version.h>
/** \page glib-mainloop GLIB Main Loop Bindings
*
diff --git a/src/pulse/i18n.h b/src/pulse/i18n.h
index 4c0ef9d..f91c0bf 100644
--- a/src/pulse/i18n.h
+++ b/src/pulse/i18n.h
@@ -24,6 +24,7 @@
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
+#include <pulse/version.h>
PA_C_DECL_BEGIN
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index 972b454..d8a28ff 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -32,6 +32,7 @@
#include <pulse/channelmap.h>
#include <pulse/volume.h>
#include <pulse/proplist.h>
+#include <pulse/version.h>
/** \page introspect Server Query and Control
*
diff --git a/src/pulse/mainloop-api.h b/src/pulse/mainloop-api.h
index 53c7411..e353ed9 100644
--- a/src/pulse/mainloop-api.h
+++ b/src/pulse/mainloop-api.h
@@ -27,6 +27,7 @@
#include <time.h>
#include <pulse/cdecl.h>
+#include <pulse/version.h>
/** \file
*
diff --git a/src/pulse/operation.h b/src/pulse/operation.h
index 188e2cb..b68e781 100644
--- a/src/pulse/operation.h
+++ b/src/pulse/operation.h
@@ -24,6 +24,7 @@
#include <pulse/cdecl.h>
#include <pulse/def.h>
+#include <pulse/version.h>
/** \file
* Asynchronous operations */
diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index 529871f..984a656 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -26,6 +26,7 @@
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
+#include <pulse/version.h>
PA_C_DECL_BEGIN
diff --git a/src/pulse/sample.h b/src/pulse/sample.h
index 3ba13db..45a481f 100644
--- a/src/pulse/sample.h
+++ b/src/pulse/sample.h
@@ -30,6 +30,7 @@
#include <pulse/gccmacro.h>
#include <pulse/cdecl.h>
+#include <pulse/version.h>
/** \page sample Sample Format Specifications
*
diff --git a/src/pulse/scache.h b/src/pulse/scache.h
index f380b4e..69e813c 100644
--- a/src/pulse/scache.h
+++ b/src/pulse/scache.h
@@ -28,6 +28,7 @@
#include <pulse/context.h>
#include <pulse/stream.h>
#include <pulse/cdecl.h>
+#include <pulse/version.h>
/** \page scache Sample Cache
*
diff --git a/src/pulse/simple.h b/src/pulse/simple.h
index a1380a0..3f57a65 100644
--- a/src/pulse/simple.h
+++ b/src/pulse/simple.h
@@ -29,6 +29,7 @@
#include <pulse/channelmap.h>
#include <pulse/def.h>
#include <pulse/cdecl.h>
+#include <pulse/version.h>
/** \page simple Simple API
*
diff --git a/src/pulse/subscribe.h b/src/pulse/subscribe.h
index 0e4be8c..2707cec 100644
--- a/src/pulse/subscribe.h
+++ b/src/pulse/subscribe.h
@@ -28,6 +28,7 @@
#include <pulse/def.h>
#include <pulse/context.h>
#include <pulse/cdecl.h>
+#include <pulse/version.h>
/** \page subscribe Event Subscription
*
diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h
index 521e29b..4de338a 100644
--- a/src/pulse/thread-mainloop.h
+++ b/src/pulse/thread-mainloop.h
@@ -25,6 +25,7 @@
#include <pulse/mainloop-api.h>
#include <pulse/cdecl.h>
+#include <pulse/version.h>
PA_C_DECL_BEGIN
diff --git a/src/pulse/utf8.h b/src/pulse/utf8.h
index 6c7e7a5..4d75195 100644
--- a/src/pulse/utf8.h
+++ b/src/pulse/utf8.h
@@ -25,6 +25,7 @@
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
+#include <pulse/version.h>
/** \file
* UTF8 Validation functions
diff --git a/src/pulse/util.h b/src/pulse/util.h
index cf06d4f..f6dd40c 100644
--- a/src/pulse/util.h
+++ b/src/pulse/util.h
@@ -27,6 +27,7 @@
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
+#include <pulse/version.h>
/** \file
* Assorted utility functions */
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index c8b73f4..e8670ab 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -29,6 +29,7 @@
#include <pulse/gccmacro.h>
#include <pulse/sample.h>
#include <pulse/channelmap.h>
+#include <pulse/version.h>
/** \page volume Volume Control
*
diff --git a/src/pulse/xmalloc.h b/src/pulse/xmalloc.h
index b264358..c30d4df 100644
--- a/src/pulse/xmalloc.h
+++ b/src/pulse/xmalloc.h
@@ -29,6 +29,7 @@
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
+#include <pulse/version.h>
/** \file
* Memory allocation functions.
commit df8ad5d18fe67b93393fb6f81d7598a95d021680
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 02:37:13 2009 +0100
add a few missing doxygen comments
diff --git a/src/pulse/gccmacro.h b/src/pulse/gccmacro.h
index 0533b10..0b1a1a6 100644
--- a/src/pulse/gccmacro.h
+++ b/src/pulse/gccmacro.h
@@ -22,6 +22,9 @@
USA.
***/
+/** \file
+ * GCC attribute macros */
+
#ifdef __GNUC__
#define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b)))
#else
@@ -100,6 +103,7 @@
#else
/** Macro for usage of GCC's alloc_size attribute */
#define PA_GCC_ALLOC_SIZE(x)
+/** Macro for usage of GCC's alloc_size attribute */
#define PA_GCC_ALLOC_SIZE2(x,y)
#endif
#endif
diff --git a/src/pulse/mainloop-signal.h b/src/pulse/mainloop-signal.h
index a6c16f2..a9e250b 100644
--- a/src/pulse/mainloop-signal.h
+++ b/src/pulse/mainloop-signal.h
@@ -40,8 +40,10 @@ PA_C_DECL_BEGIN
/** An opaque UNIX signal event source object */
typedef struct pa_signal_event pa_signal_event;
+/** Callback prototype for signal events */
typedef void (*pa_signal_cb_t) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata);
+/** Destroy callback prototype for signal events */
typedef void (*pa_signal_destroy_cb_t) (pa_mainloop_api *api, pa_signal_event*e, void *userdata);
/** Initialize the UNIX signal subsystem and bind it to the specified main loop */
diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index 984a656..203a28c 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -162,7 +162,7 @@ int pa_proplist_setf(pa_proplist *p, const char *key, const char *format, ...) P
* internal copy of the data passed is made. \since 0.9.11 */
int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nbytes);
-/* Return a string entry for the specified key. Will return NULL if
+/** Return a string entry for the specified key. Will return NULL if
* the data is not valid UTF-8. Will return a NUL-terminated string in
* an internally allocated buffer. The caller should make a copy of
* the data before accessing the property list again. \since 0.9.11 */
diff --git a/src/pulse/timeval.h b/src/pulse/timeval.h
index ee39829..2b3faf1 100644
--- a/src/pulse/timeval.h
+++ b/src/pulse/timeval.h
@@ -26,17 +26,29 @@
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
#include <pulse/sample.h>
+#include <pulse/version.h>
/** \file
* Utility functions for handling timeval calculations */
PA_C_DECL_BEGIN
+/** The number of milliseconds in a second */
#define PA_MSEC_PER_SEC ((pa_usec_t) 1000ULL)
+
+/** The number of microseconds in a second */
#define PA_USEC_PER_SEC ((pa_usec_t) 1000000ULL)
+
+/** The number of nanoseconds in a second */
#define PA_NSEC_PER_SEC ((pa_usec_t) 1000000000ULL)
+
+/** The number of microseconds in a millisecond */
#define PA_USEC_PER_MSEC ((pa_usec_t) 1000ULL)
+
+/** The number of nanoseconds in a millisecond */
#define PA_NSEC_PER_MSEC ((pa_usec_t) 1000000ULL)
+
+/** The number of nanoseconds in a microsecond */
#define PA_NSEC_PER_USEC ((pa_usec_t) 1000ULL)
struct timeval;
commit 5449d793ae7800ad236f027f6c6893a1d2db3929
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 02:45:37 2009 +0100
swap argument order of pa_cvolume_get_balance() to be a bit more systematic
diff --git a/src/pulse/volume.c b/src/pulse/volume.c
index 2c97784..822fe39 100644
--- a/src/pulse/volume.c
+++ b/src/pulse/volume.c
@@ -435,7 +435,7 @@ static void get_avg_lr(const pa_channel_map *map, const pa_cvolume *v, pa_volume
*r = right / n_right;
}
-float pa_cvolume_get_balance(const pa_channel_map *map, const pa_cvolume *v) {
+float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) {
pa_volume_t left, right;
pa_assert(v);
@@ -462,7 +462,7 @@ float pa_cvolume_get_balance(const pa_channel_map *map, const pa_cvolume *v) {
return 1.0f - ((float) left / (float) right);
}
-pa_cvolume* pa_cvolume_set_balance(const pa_channel_map *map, pa_cvolume *v, float new_balance) {
+pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) {
pa_volume_t left, nleft, right, nright, m;
unsigned c;
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index e8670ab..c1967b3 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -237,7 +237,7 @@ int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) PA_GCC_
/** Calculate a 'balance' value for the specified volume with the
* specified channel map. The return value will range from -1.0f
* (left) to +1.0f (right) \since 0.9.15 */
-float pa_cvolume_get_balance(const pa_channel_map *map, const pa_cvolume *v) PA_GCC_PURE;
+float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) PA_GCC_PURE;
/** Adjust the 'balance' value for the specified volume with the
* specified channel map. v will be modified in place and
@@ -246,7 +246,7 @@ float pa_cvolume_get_balance(const pa_channel_map *map, const pa_cvolume *v) PA_
* pa_cvolume_get_balance() is not guaranteed to actually return the
* requested balance (e.g. when the input volume was zero anyway for
* all channels) \since 0.9.15 */
-pa_cvolume* pa_cvolume_set_balance(const pa_channel_map *map, pa_cvolume *v, float new_balance);
+pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance);
/** Scale the passed pa_cvolume structure so that the maximum volume
* of all channels equals max. The proportions between the channel
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 7f3a745..e87abe0 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -261,7 +261,7 @@ char *pa_sink_list_to_string(pa_core *c) {
pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)),
sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE)) : "",
- pa_cvolume_get_balance(&sink->channel_map, pa_sink_get_volume(sink, FALSE)),
+ pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE), &sink->channel_map),
pa_volume_snprint(v, sizeof(v), sink->base_volume),
sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), sink->base_volume) : "",
@@ -349,7 +349,7 @@ char *pa_source_list_to_string(pa_core *c) {
pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source, FALSE)),
source->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
source->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_source_get_volume(source, FALSE)) : "",
- pa_cvolume_get_balance(&source->channel_map, pa_source_get_volume(source, FALSE)),
+ pa_cvolume_get_balance(pa_source_get_volume(source, FALSE), &source->channel_map),
pa_volume_snprint(v, sizeof(v), source->base_volume),
source->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
source->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), source->base_volume) : "",
@@ -519,7 +519,7 @@ char *pa_sink_input_list_to_string(pa_core *c) {
i->sink->index, i->sink->name,
pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)),
pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_input_get_volume(i)),
- pa_cvolume_get_balance(&i->channel_map, pa_sink_input_get_volume(i)),
+ pa_cvolume_get_balance(pa_sink_input_get_volume(i), &i->channel_map),
pa_yes_no(pa_sink_input_get_mute(i)),
(double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC,
clt,
@@ -590,7 +590,7 @@ char *pa_scache_list_to_string(pa_core *c) {
l,
pa_cvolume_snprint(cv, sizeof(cv), &e->volume),
pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &e->volume),
- e->memchunk.memblock ? pa_cvolume_get_balance(&e->channel_map, &e->volume) : 0.0f,
+ e->memchunk.memblock ? pa_cvolume_get_balance(&e->volume, &e->channel_map) : 0.0f,
pa_yes_no(e->lazy),
e->filename ? e->filename : "n/a");
diff --git a/src/tests/voltest.c b/src/tests/voltest.c
index 879d86b..0c6d2ea 100644
--- a/src/tests/voltest.c
+++ b/src/tests/voltest.c
@@ -38,7 +38,7 @@ int main(int argc, char *argv[]) {
for (cv.values[1] = PA_VOLUME_MUTED; cv.values[1] <= PA_VOLUME_NORM*2; cv.values[1] += 4096) {
char s[PA_CVOLUME_SNPRINT_MAX];
- printf("Volume: [%s]; balance: %2.1f\n", pa_cvolume_snprint(s, sizeof(s), &cv), pa_cvolume_get_balance(&map, &cv));
+ printf("Volume: [%s]; balance: %2.1f\n", pa_cvolume_snprint(s, sizeof(s), &cv), pa_cvolume_get_balance(&cv, &map));
}
for (cv.values[0] = PA_VOLUME_MUTED+4096; cv.values[0] <= PA_VOLUME_NORM*2; cv.values[0] += 4096)
@@ -48,12 +48,12 @@ int main(int argc, char *argv[]) {
pa_cvolume r;
float k;
- printf("Before: volume: [%s]; balance: %2.1f\n", pa_cvolume_snprint(s, sizeof(s), &cv), pa_cvolume_get_balance(&map, &cv));
+ printf("Before: volume: [%s]; balance: %2.1f\n", pa_cvolume_snprint(s, sizeof(s), &cv), pa_cvolume_get_balance(&cv, &map));
r = cv;
- pa_cvolume_set_balance(&map, &r, b);
+ pa_cvolume_set_balance(&r, &map,b);
- k = pa_cvolume_get_balance(&map, &r);
+ k = pa_cvolume_get_balance(&r, &map);
printf("After: volume: [%s]; balance: %2.1f (intended: %2.1f) %s\n", pa_cvolume_snprint(s, sizeof(s), &r), k, b, k < b-.05 || k > b+.5 ? "MISMATCH" : "");
}
diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index 0820641..154e7f9 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -216,7 +216,7 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_
pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
- pa_cvolume_get_balance(&i->channel_map, &i->volume),
+ pa_cvolume_get_balance(&i->volume, &i->channel_map),
pa_volume_snprint(v, sizeof(v), i->base_volume),
i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
@@ -296,7 +296,7 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int
pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
- pa_cvolume_get_balance(&i->channel_map, &i->volume),
+ pa_cvolume_get_balance(&i->volume, &i->channel_map),
pa_volume_snprint(v, sizeof(v), i->base_volume),
i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
@@ -483,7 +483,7 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info
pa_yes_no(i->mute),
pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
- pa_cvolume_get_balance(&i->channel_map, &i->volume),
+ pa_cvolume_get_balance(&i->volume, &i->channel_map),
(double) i->buffer_usec,
(double) i->sink_usec,
i->resample_method ? i->resample_method : _("n/a"),
@@ -584,7 +584,7 @@ static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int
pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : _("n/a"),
pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
- pa_cvolume_get_balance(&i->channel_map, &i->volume),
+ pa_cvolume_get_balance(&i->volume, &i->channel_map),
(double) i->duration/1000000.0,
t,
pa_yes_no(i->lazy),
commit 1be39e4fa5b8f6a2d995593a4c1fd66eeafd6328
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 03:05:40 2009 +0100
allow samples to be played with 'default' (i.e. unspecified) volume.
diff --git a/src/pulse/scache.c b/src/pulse/scache.c
index fd3b987..c96c42a 100644
--- a/src/pulse/scache.c
+++ b/src/pulse/scache.c
@@ -188,6 +188,10 @@ pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char
t = pa_tagstruct_command(c, PA_COMMAND_PLAY_SAMPLE, &tag);
pa_tagstruct_putu32(t, PA_INVALID_INDEX);
pa_tagstruct_puts(t, dev);
+
+ if (volume == (pa_volume_t) -1 && c->version < 15)
+ volume = PA_VOLUME_NORM;
+
pa_tagstruct_putu32(t, volume);
pa_tagstruct_puts(t, name);
@@ -225,6 +229,10 @@ pa_operation *pa_context_play_sample_with_proplist(pa_context *c, const char *na
t = pa_tagstruct_command(c, PA_COMMAND_PLAY_SAMPLE, &tag);
pa_tagstruct_putu32(t, PA_INVALID_INDEX);
pa_tagstruct_puts(t, dev);
+
+ if (volume == (pa_volume_t) -1 && c->version < 15)
+ volume = PA_VOLUME_NORM;
+
pa_tagstruct_putu32(t, volume);
pa_tagstruct_puts(t, name);
pa_tagstruct_put_proplist(t, p);
diff --git a/src/pulse/scache.h b/src/pulse/scache.h
index 69e813c..79fcfbc 100644
--- a/src/pulse/scache.h
+++ b/src/pulse/scache.h
@@ -101,7 +101,7 @@ pa_operation* pa_context_play_sample(
pa_context *c /**< Context */,
const char *name /**< Name of the sample to play */,
const char *dev /**< Sink to play this sample on */,
- pa_volume_t volume /**< Volume to play this sample with */ ,
+ pa_volume_t volume /**< Volume to play this sample with. Starting with 0.9.15 you may pass here (pa_volume_t) -1 which will leave the decision about the volume to the server side which is a good idea. */ ,
pa_context_success_cb_t cb /**< Call this function after successfully starting playback, or NULL */,
void *userdata /**< Userdata to pass to the callback */);
@@ -113,7 +113,7 @@ pa_operation* pa_context_play_sample_with_proplist(
pa_context *c /**< Context */,
const char *name /**< Name of the sample to play */,
const char *dev /**< Sink to play this sample on */,
- pa_volume_t volume /**< Volume to play this sample with */ ,
+ pa_volume_t volume /**< Volume to play this sample with. Starting with 0.9.15 you may pass here (pa_volume_t) -1 which will leave the decision about the volume to the server side which is a good idea. */ ,
pa_proplist *proplist /**< Property list for this sound. The property list of the cached entry will be merged into this property list */,
pa_context_play_sample_cb_t cb /**< Call this function after successfully starting playback, or NULL */,
void *userdata /**< Userdata to pass to the callback */);
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index e87abe0..c74ca5d 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -588,9 +588,9 @@ char *pa_scache_list_to_string(pa_core *c) {
cmn ? cmn : "",
(long unsigned)(e->memchunk.memblock ? e->memchunk.length : 0),
l,
- pa_cvolume_snprint(cv, sizeof(cv), &e->volume),
- pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &e->volume),
- e->memchunk.memblock ? pa_cvolume_get_balance(&e->volume, &e->channel_map) : 0.0f,
+ e->volume_is_set ? pa_cvolume_snprint(cv, sizeof(cv), &e->volume) : "n/a",
+ e->volume_is_set ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &e->volume) : "n/a",
+ (e->memchunk.memblock && e->volume_is_set) ? pa_cvolume_get_balance(&e->volume, &e->channel_map) : 0.0f,
pa_yes_no(e->lazy),
e->filename ? e->filename : "n/a");
diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c
index 0f34c9d..6d2ae93 100644
--- a/src/pulsecore/core-scache.c
+++ b/src/pulsecore/core-scache.c
@@ -137,6 +137,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) {
pa_sample_spec_init(&e->sample_spec);
pa_channel_map_init(&e->channel_map);
pa_cvolume_init(&e->volume);
+ e->volume_is_set = FALSE;
pa_proplist_sets(e->proplist, PA_PROP_MEDIA_ROLE, "event");
@@ -175,6 +176,7 @@ int pa_scache_add_item(
pa_sample_spec_init(&e->sample_spec);
pa_channel_map_init(&e->channel_map);
pa_cvolume_init(&e->volume);
+ e->volume_is_set = FALSE;
if (ss) {
e->sample_spec = *ss;
@@ -308,6 +310,7 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t
pa_scache_entry *e;
pa_cvolume r;
pa_proplist *merged;
+ pa_bool_t pass_volume;
pa_assert(c);
pa_assert(name);
@@ -324,10 +327,12 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t
pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index);
- if (pa_cvolume_valid(&e->volume))
- pa_cvolume_remap(&e->volume, &old_channel_map, &e->channel_map);
- else
- pa_cvolume_reset(&e->volume, e->sample_spec.channels);
+ if (e->volume_is_set) {
+ if (pa_cvolume_valid(&e->volume))
+ pa_cvolume_remap(&e->volume, &old_channel_map, &e->channel_map);
+ else
+ pa_cvolume_reset(&e->volume, e->sample_spec.channels);
+ }
}
if (!e->memchunk.memblock)
@@ -335,19 +340,26 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t
pa_log_debug("Playing sample \"%s\" on \"%s\"", name, sink->name);
- pa_cvolume_set(&r, e->volume.channels, volume);
- pa_sw_cvolume_multiply(&r, &r, &e->volume);
+ pass_volume = TRUE;
- merged = pa_proplist_new();
+ if (e->volume_is_set && volume != (pa_volume_t) -1) {
+ pa_cvolume_set(&r, e->sample_spec.channels, volume);
+ pa_sw_cvolume_multiply(&r, &r, &e->volume);
+ } else if (e->volume_is_set)
+ r = e->volume;
+ else if (volume != (pa_volume_t) -1)
+ pa_cvolume_set(&r, e->sample_spec.channels, volume);
+ else
+ pass_volume = FALSE;
+ merged = pa_proplist_new();
pa_proplist_setf(merged, PA_PROP_MEDIA_NAME, "Sample %s", name);
-
pa_proplist_update(merged, PA_UPDATE_REPLACE, e->proplist);
if (p)
pa_proplist_update(merged, PA_UPDATE_REPLACE, p);
- if (pa_play_memchunk(sink, &e->sample_spec, &e->channel_map, &e->memchunk, &r, merged, sink_input_idx) < 0) {
+ if (pa_play_memchunk(sink, &e->sample_spec, &e->channel_map, &e->memchunk, pass_volume ? &r : NULL, merged, sink_input_idx) < 0) {
pa_proplist_free(merged);
return -1;
}
diff --git a/src/pulsecore/core-scache.h b/src/pulsecore/core-scache.h
index ba65a96..a75f8ac 100644
--- a/src/pulsecore/core-scache.h
+++ b/src/pulsecore/core-scache.h
@@ -36,6 +36,7 @@ typedef struct pa_scache_entry {
char *name;
pa_cvolume volume;
+ pa_bool_t volume_is_set;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
pa_memchunk memchunk;
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 7ddc010..3896dff 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -2840,6 +2840,7 @@ static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *
static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
pa_sample_spec fixed_ss;
+ pa_cvolume v;
pa_assert(t);
pa_assert(e);
@@ -2851,7 +2852,13 @@ static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s
pa_tagstruct_putu32(t, e->index);
pa_tagstruct_puts(t, e->name);
- pa_tagstruct_put_cvolume(t, &e->volume);
+
+ if (e->volume_is_set)
+ v = e->volume;
+ else
+ pa_cvolume_init(&v);
+
+ pa_tagstruct_put_cvolume(t, &v);
pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
pa_tagstruct_put_sample_spec(t, &fixed_ss);
pa_tagstruct_put_channel_map(t, &e->channel_map);
commit eca32235fb38961cf27aa741219fd7c184d73d1e
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 04:29:25 2009 +0100
get rid of module-flat-volumes since we are moving this into the core
diff --git a/src/Makefile.am b/src/Makefile.am
index f313bb5..00dd53d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -863,7 +863,6 @@ libavahi_wrap_la_LIBADD = $(AM_LIBADD) $(AVAHI_CFLAGS) libpulsecore- at PA_MAJORMIN
###################################
modlibexec_LTLIBRARIES += \
- module-flat-volume.la \
module-cli.la \
module-cli-protocol-tcp.la \
module-simple-protocol-tcp.la \
@@ -1086,8 +1085,7 @@ SYMDEF_FILES = \
modules/module-raop-discover-symdef.h \
modules/gconf/module-gconf-symdef.h \
modules/module-position-event-sounds-symdef.h \
- modules/module-console-kit-symdef.h \
- modules/module-flat-volume-symdef.h
+ modules/module-console-kit-symdef.h
EXTRA_DIST += $(SYMDEF_FILES)
BUILT_SOURCES += $(SYMDEF_FILES)
@@ -1096,12 +1094,6 @@ $(SYMDEF_FILES): modules/module-defs.h.m4
$(MKDIR_P) $(dir $@)
$(M4) -Dfname="$@" $< > $@
-# Flat volume
-
-module_flat_volume_la_SOURCES = modules/module-flat-volume.c
-module_flat_volume_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_flat_volume_la_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINORMICRO@.la libpulsecommon- at PA_MAJORMINORMICRO@.la libpulse.la
-
# Simple protocol
module_simple_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c
diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
index d761f5f..5d69926 100755
--- a/src/daemon/default.pa.in
+++ b/src/daemon/default.pa.in
@@ -77,9 +77,6 @@ load-module module-native-protocol-unix
#load-module module-null-sink sink_name=rtp format=s16be channels=2 rate=44100 description="RTP Multicast Sink"
#load-module module-rtp-send source=rtp.monitor
-### Enable flat volumes where possible
-load-module module-flat-volume
-
### Automatically restore the default sink/source when changed by the user during runtime
load-module module-default-device-restore
diff --git a/src/modules/module-flat-volume.c b/src/modules/module-flat-volume.c
deleted file mode 100644
index fe6dc92..0000000
--- a/src/modules/module-flat-volume.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/***
- This file is part of PulseAudio.
-
- Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- Copyright 2004-2006, 2008 Lennart Poettering
-
- Contact: Marc-Andre Lureau <marc-andre.lureau at nokia.com>
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <regex.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <pulse/xmalloc.h>
-
-#include <pulsecore/core-error.h>
-#include <pulsecore/module.h>
-#include <pulsecore/core-util.h>
-#include <pulsecore/log.h>
-#include <pulsecore/sink-input.h>
-#include <pulsecore/core-util.h>
-#include <pulsecore/macro.h>
-
-#include "module-flat-volume-symdef.h"
-
-PA_MODULE_AUTHOR("Marc-Andre Lureau");
-PA_MODULE_DESCRIPTION("Flat volume");
-PA_MODULE_VERSION(PACKAGE_VERSION);
-PA_MODULE_LOAD_ONCE(TRUE);
-PA_MODULE_USAGE("");
-
-struct userdata {
- pa_subscription *subscription;
- pa_hook_slot *sink_input_set_volume_hook_slot;
- pa_hook_slot *sink_input_fixate_hook_slot;
-};
-
-static void process_input_volume_change(
- pa_cvolume *dest_volume,
- const pa_cvolume *dest_virtual_volume,
- pa_channel_map *dest_channel_map,
- pa_sink_input *this,
- pa_sink *sink) {
-
- pa_sink_input *i;
- uint32_t idx;
- pa_cvolume max_volume, sink_volume;
-
- pa_assert(dest_volume);
- pa_assert(dest_virtual_volume);
- pa_assert(dest_channel_map);
- pa_assert(sink);
-
- if (!(sink->flags & PA_SINK_DECIBEL_VOLUME))
- return;
-
- pa_log_debug("Sink input volume changed");
-
- max_volume = *dest_virtual_volume;
- pa_cvolume_remap(&max_volume, dest_channel_map, &sink->channel_map);
-
- for (i = PA_SINK_INPUT(pa_idxset_first(sink->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(sink->inputs, &idx))) {
- /* skip this sink-input if we are processing a volume change request */
- if (this && this == i)
- continue;
-
- if (pa_cvolume_max(&i->virtual_volume) > pa_cvolume_max(&max_volume)) {
- max_volume = i->virtual_volume;
- pa_cvolume_remap(&max_volume, &i->channel_map, &sink->channel_map);
- }
- }
-
- /* Set the master volume, and normalize inputs */
- if (!pa_cvolume_equal(&max_volume, pa_sink_get_volume(sink, TRUE))) {
-
- pa_sink_set_volume(sink, &max_volume);
-
- pa_log_debug("sink = %.2f (changed)", (double)pa_cvolume_avg(pa_sink_get_volume(sink, TRUE))/PA_VOLUME_NORM);
-
- /* Now, normalize each of the internal volume (client sink-input volume / sink master volume) */
- for (i = PA_SINK_INPUT(pa_idxset_first(sink->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(sink->inputs, &idx))) {
- /* skip this sink-input if we are processing a volume change request */
- if (this && this == i)
- continue;
-
- sink_volume = max_volume;
- pa_cvolume_remap(&sink_volume, &sink->channel_map, &i->channel_map);
- pa_sw_cvolume_divide(&i->volume, &i->virtual_volume, &sink_volume);
- pa_log_debug("sink input { id = %d, flat = %.2f, true = %.2f }",
- i->index,
- (double)pa_cvolume_avg(&i->virtual_volume)/PA_VOLUME_NORM,
- (double)pa_cvolume_avg(&i->volume)/PA_VOLUME_NORM);
- pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, &i->volume, 1), 0, NULL, pa_xfree);
- }
- } else
- pa_log_debug("sink = %.2f", (double)pa_cvolume_avg(pa_sink_get_volume(sink, TRUE))/PA_VOLUME_NORM);
-
- /* and this one */
-
- sink_volume = max_volume;
- pa_cvolume_remap(&sink_volume, &sink->channel_map, dest_channel_map);
- pa_sw_cvolume_divide(dest_volume, dest_virtual_volume, &sink_volume);
- pa_log_debug("caller sink input: { id = %d, flat = %.2f, true = %.2f }",
- this ? (int)this->index : -1,
- (double)pa_cvolume_avg(dest_virtual_volume)/PA_VOLUME_NORM,
- (double)pa_cvolume_avg(dest_volume)/PA_VOLUME_NORM);
-}
-
-static pa_hook_result_t sink_input_set_volume_hook_callback(pa_core *c, pa_sink_input_set_volume_data *this, struct userdata *u) {
- pa_assert(this);
- pa_assert(this->sink_input);
-
- process_input_volume_change(&this->volume, &this->virtual_volume, &this->sink_input->channel_map,
- this->sink_input, this->sink_input->sink);
-
- return PA_HOOK_OK;
-}
-
-static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *core, pa_sink_input_new_data *this, struct userdata *u) {
- pa_assert(this);
- pa_assert(this->sink);
-
- process_input_volume_change(&this->volume, &this->virtual_volume, &this->channel_map,
- NULL, this->sink);
-
- return PA_HOOK_OK;
-}
-
-static void subscribe_callback(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
- struct userdata *u = userdata;
- pa_sink *sink;
- pa_sink_input *i;
- uint32_t iidx;
- pa_cvolume sink_volume;
-
- pa_assert(core);
- pa_assert(u);
-
- if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
- t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE))
- return;
-
- if (!(sink = pa_idxset_get_by_index(core->sinks, idx)))
- return;
-
- if (!(sink->flags & PA_SINK_DECIBEL_VOLUME))
- return;
-
- pa_log_debug("Sink volume changed");
- pa_log_debug("sink = %.2f", (double)pa_cvolume_avg(pa_sink_get_volume(sink, TRUE)) / PA_VOLUME_NORM);
-
- sink_volume = *pa_sink_get_volume(sink, TRUE);
-
- for (i = PA_SINK_INPUT(pa_idxset_first(sink->inputs, &iidx)); i; i = PA_SINK_INPUT(pa_idxset_next(sink->inputs, &iidx))) {
- pa_cvolume si_volume;
-
- si_volume = sink_volume;
- pa_cvolume_remap(&si_volume, &sink->channel_map, &i->channel_map);
- pa_sw_cvolume_multiply(&i->virtual_volume, &i->volume, &si_volume);
- pa_log_debug("sink input = { id = %d, flat = %.2f, true = %.2f }",
- i->index,
- (double)pa_cvolume_avg(&i->virtual_volume)/PA_VOLUME_NORM,
- (double)pa_cvolume_avg(&i->volume)/PA_VOLUME_NORM);
- pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
- }
-}
-
-int pa__init(pa_module*m) {
- struct userdata *u;
-
- pa_assert(m);
-
- u = pa_xnew(struct userdata, 1);
- m->userdata = u;
-
- u->sink_input_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_fixate_hook_callback, u);
- u->sink_input_set_volume_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_set_volume_hook_callback, u);
-
- u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK, subscribe_callback, u);
-
- return 0;
-}
-
-void pa__done(pa_module*m) {
- struct userdata* u;
-
- pa_assert(m);
-
- if (!(u = m->userdata))
- return;
-
- if (u->subscription)
- pa_subscription_free(u->subscription);
-
- if (u->sink_input_set_volume_hook_slot)
- pa_hook_slot_free(u->sink_input_set_volume_hook_slot);
- if (u->sink_input_fixate_hook_slot)
- pa_hook_slot_free(u->sink_input_fixate_hook_slot);
-
- pa_xfree(u);
-}
commit 4bfa5d7d13350bd0eac439dbe251812ce437ea43
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 04:35:11 2009 +0100
fix size calculation
diff --git a/src/pulsecore/bitset.h b/src/pulsecore/bitset.h
index 21e840a..95f5cfc 100644
--- a/src/pulsecore/bitset.h
+++ b/src/pulsecore/bitset.h
@@ -26,7 +26,7 @@
#include <pulsecore/macro.h>
#define PA_BITSET_ELEMENTS(n) (((n)+31)/32)
-#define PA_BITSET_SIZE(n) (PA_BITSET_ELEMENTS(n)*32)
+#define PA_BITSET_SIZE(n) (PA_BITSET_ELEMENTS(n)*4)
typedef uint32_t pa_bitset_t;
commit d5f46e824e3f8a042e6f67dd4c3fc385545edd74
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Jan 27 04:39:07 2009 +0100
move flat volume logic into the core. while doing so add n_volume_steps field to sinks/sources
diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in
index a516ee3..9ddcd6a 100644
--- a/man/pulse-daemon.conf.5.xml.in
+++ b/man/pulse-daemon.conf.5.xml.in
@@ -140,7 +140,6 @@ USA.
precedence.</p>
</option>
-
<option>
<p><opt>system-instance=</opt> Run the daemon as system-wide
instance, requires root priviliges. Takes a boolean argument,
@@ -148,7 +147,6 @@ USA.
argument takes precedence.</p>
</option>
-
<option>
<p><opt>disable-shm=</opt> Disable data transfer via POSIX
shared memory. Takes a boolean argument, defaults to
@@ -165,6 +163,13 @@ USA.
memory overcommit.</p>
</option>
+ <option>
+ <p><opt>flat-volumes=</opt> Enable 'flat' volumes, i.e. where
+ possible let the sink volume equal the maximum of the volumes of
+ the inputs connected to it. Takes a boolean argument, defaults
+ to <opt>yes</opt>.</p>
+ </option>
+
</section>
<section name="Scheduling">
diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index c8c1b6f..279fb7b 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -64,6 +64,7 @@ static const pa_daemon_conf default_conf = {
.realtime_priority = 5, /* Half of JACK's default rtprio */
.disallow_module_loading = FALSE,
.disallow_exit = FALSE,
+ .flat_volumes = TRUE,
.exit_idle_time = 20,
.scache_idle_time = 20,
.auto_log_target = 1,
@@ -418,6 +419,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
{ "system-instance", pa_config_parse_bool, NULL },
{ "no-cpu-limit", pa_config_parse_bool, NULL },
{ "disable-shm", pa_config_parse_bool, NULL },
+ { "flat-volumes", pa_config_parse_bool, NULL },
{ "exit-idle-time", pa_config_parse_int, NULL },
{ "scache-idle-time", pa_config_parse_int, NULL },
{ "realtime-priority", parse_rtprio, NULL },
@@ -490,6 +492,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
table[i++].data = &c->system_instance;
table[i++].data = &c->no_cpu_limit;
table[i++].data = &c->disable_shm;
+ table[i++].data = &c->flat_volumes;
table[i++].data = &c->exit_idle_time;
table[i++].data = &c->scache_idle_time;
table[i++].data = c;
@@ -650,6 +653,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
pa_strbuf_printf(s, "system-instance = %s\n", pa_yes_no(c->system_instance));
pa_strbuf_printf(s, "no-cpu-limit = %s\n", pa_yes_no(c->no_cpu_limit));
pa_strbuf_printf(s, "disable-shm = %s\n", pa_yes_no(c->disable_shm));
+ pa_strbuf_printf(s, "flat-volumes = %s\n", pa_yes_no(c->flat_volumes));
pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time);
pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time);
pa_strbuf_printf(s, "dl-search-path = %s\n", pa_strempty(c->dl_search_path));
diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h
index 3b75b83..aa9d298 100644
--- a/src/daemon/daemon-conf.h
+++ b/src/daemon/daemon-conf.h
@@ -70,7 +70,8 @@ typedef struct pa_daemon_conf {
load_default_script_file,
disallow_exit,
log_meta,
- log_time;
+ log_time,
+ flat_volumes;
int exit_idle_time,
scache_idle_time,
auto_log_target,
diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in
index 00a9593..69d17f2 100644
--- a/src/daemon/daemon.conf.in
+++ b/src/daemon/daemon.conf.in
@@ -53,6 +53,8 @@
; disable-remixing = no
; disable-lfe-remixing = yes
+; flat-volumes = yes
+
; no-cpu-limit = no
; rlimit-fsize = -1
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 9705f4c..bd8ad1d 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -917,6 +917,7 @@ int main(int argc, char *argv[]) {
c->disable_lfe_remixing = !!conf->disable_lfe_remixing;
c->running_as_daemon = !!conf->daemonize;
c->disallow_exit = conf->disallow_exit;
+ c->flat_volumes = conf->flat_volumes;
pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0);
pa_signal_new(SIGINT, signal_callback, c);
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 5020eac..3503c4a 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -757,7 +757,7 @@ static long to_alsa_volume(struct userdata *u, pa_volume_t vol) {
return PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
}
-static int sink_get_volume_cb(pa_sink *s) {
+static void sink_get_volume_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int err;
unsigned i;
@@ -820,27 +820,24 @@ static int sink_get_volume_cb(pa_sink *s) {
if (!pa_cvolume_equal(&u->hardware_volume, &r)) {
- u->hardware_volume = s->volume = r;
+ s->virtual_volume = u->hardware_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;
+ return;
fail:
pa_log_error("Unable to read volume: %s", snd_strerror(err));
-
- return -1;
}
-static int sink_set_volume_cb(pa_sink *s) {
+static void sink_set_volume_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int err;
unsigned i;
@@ -857,7 +854,7 @@ static int sink_set_volume_cb(pa_sink *s) {
long alsa_vol;
pa_volume_t vol;
- vol = s->volume.values[i];
+ vol = s->virtual_volume.values[i];
if (u->hw_dB_supported) {
@@ -894,7 +891,7 @@ static int sink_set_volume_cb(pa_sink *s) {
pa_volume_t vol;
long alsa_vol;
- vol = pa_cvolume_max(&s->volume);
+ vol = pa_cvolume_max(&s->virtual_volume);
if (u->hw_dB_supported) {
alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
@@ -911,7 +908,7 @@ static int sink_set_volume_cb(pa_sink *s) {
VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
#endif
- pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0));
+ pa_cvolume_set(&r, s->sample_spec.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0));
} else {
alsa_vol = to_alsa_volume(u, vol);
@@ -932,11 +929,9 @@ static int sink_set_volume_cb(pa_sink *s) {
char t[PA_CVOLUME_SNPRINT_MAX];
/* Match exactly what the user requested by software */
+ pa_sw_cvolume_divide(&s->soft_volume, &s->virtual_volume, &r);
- pa_sw_cvolume_divide(&r, &s->volume, &r);
- pa_sink_set_soft_volume(s, &r);
-
- pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->volume));
+ pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->virtual_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));
@@ -945,17 +940,15 @@ static int sink_set_volume_cb(pa_sink *s) {
/* We can't match exactly what the user requested, hence let's
* at least tell the user about it */
- s->volume = r;
+ s->virtual_volume = r;
- return 0;
+ return;
fail:
pa_log_error("Unable to set volume: %s", snd_strerror(err));
-
- return -1;
}
-static int sink_get_mute_cb(pa_sink *s) {
+static void sink_get_mute_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int err, sw;
@@ -964,15 +957,13 @@ static int sink_get_mute_cb(pa_sink *s) {
if ((err = snd_mixer_selem_get_playback_switch(u->mixer_elem, 0, &sw)) < 0) {
pa_log_error("Unable to get switch: %s", snd_strerror(err));
- return -1;
+ return;
}
s->muted = !sw;
-
- return 0;
}
-static int sink_set_mute_cb(pa_sink *s) {
+static void sink_set_mute_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int err;
@@ -981,10 +972,8 @@ static int sink_set_mute_cb(pa_sink *s) {
if ((err = snd_mixer_selem_set_playback_switch_all(u->mixer_elem, !s->muted)) < 0) {
pa_log_error("Unable to set switch: %s", snd_strerror(err));
- return -1;
+ return;
}
-
- return 0;
}
static void sink_update_requested_latency_cb(pa_sink *s) {
@@ -1552,6 +1541,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
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");
+ if (!u->hw_dB_supported)
+ u->sink->n_volume_steps = u->hw_volume_max - u->hw_volume_min + 1;
} else
pa_log_info("Using software volume control.");
}
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 96e0d89..c4d3418 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -703,7 +703,7 @@ static long to_alsa_volume(struct userdata *u, pa_volume_t vol) {
return PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
}
-static int source_get_volume_cb(pa_source *s) {
+static void source_get_volume_cb(pa_source *s) {
struct userdata *u = s->userdata;
int err;
unsigned i;
@@ -766,27 +766,24 @@ static int source_get_volume_cb(pa_source *s) {
if (!pa_cvolume_equal(&u->hardware_volume, &r)) {
- u->hardware_volume = s->volume = r;
+ s->virtual_volume = u->hardware_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;
+ return;
fail:
pa_log_error("Unable to read volume: %s", snd_strerror(err));
-
- return -1;
}
-static int source_set_volume_cb(pa_source *s) {
+static void source_set_volume_cb(pa_source *s) {
struct userdata *u = s->userdata;
int err;
unsigned i;
@@ -803,7 +800,7 @@ static int source_set_volume_cb(pa_source *s) {
long alsa_vol;
pa_volume_t vol;
- vol = s->volume.values[i];
+ vol = s->virtual_volume.values[i];
if (u->hw_dB_supported) {
@@ -840,7 +837,7 @@ static int source_set_volume_cb(pa_source *s) {
pa_volume_t vol;
long alsa_vol;
- vol = pa_cvolume_max(&s->volume);
+ vol = pa_cvolume_max(&s->virtual_volume);
if (u->hw_dB_supported) {
alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
@@ -857,7 +854,7 @@ static int source_set_volume_cb(pa_source *s) {
VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
#endif
- pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0));
+ pa_cvolume_set(&r, s->sample_spec.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0));
} else {
alsa_vol = to_alsa_volume(u, vol);
@@ -879,10 +876,9 @@ static int source_set_volume_cb(pa_source *s) {
/* Match exactly what the user requested by software */
- pa_sw_cvolume_divide(&r, &s->volume, &r);
- pa_source_set_soft_volume(s, &r);
+ pa_sw_cvolume_divide(&s->soft_volume, &s->virtual_volume, &r);
- pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->volume));
+ pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->virtual_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));
@@ -891,17 +887,15 @@ static int source_set_volume_cb(pa_source *s) {
/* We can't match exactly what the user requested, hence let's
* at least tell the user about it */
- s->volume = r;
+ s->virtual_volume = r;
- return 0;
+ return;
fail:
pa_log_error("Unable to set volume: %s", snd_strerror(err));
-
- return -1;
}
-static int source_get_mute_cb(pa_source *s) {
+static void source_get_mute_cb(pa_source *s) {
struct userdata *u = s->userdata;
int err, sw;
@@ -910,15 +904,13 @@ static int source_get_mute_cb(pa_source *s) {
if ((err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw)) < 0) {
pa_log_error("Unable to get switch: %s", snd_strerror(err));
- return -1;
+ return;
}
s->muted = !sw;
-
- return 0;
}
-static int source_set_mute_cb(pa_source *s) {
+static void source_set_mute_cb(pa_source *s) {
struct userdata *u = s->userdata;
int err;
@@ -927,10 +919,8 @@ static int source_set_mute_cb(pa_source *s) {
if ((err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->muted)) < 0) {
pa_log_error("Unable to set switch: %s", snd_strerror(err));
- return -1;
+ return;
}
-
- return 0;
}
static void source_update_requested_latency_cb(pa_source *s) {
@@ -1372,6 +1362,9 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
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");
+
+ if (!u->hw_dB_supported)
+ u->source->n_volume_steps = u->hw_volume_max - u->hw_volume_min + 1;
} else
pa_log_info("Using software volume control.");
}
diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c
index bbe4f7c..9a782ca 100644
--- a/src/modules/module-lirc.c
+++ b/src/modules/module-lirc.c
@@ -135,7 +135,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_NORM;
}
- pa_sink_set_volume(s, &cv);
+ pa_sink_set_volume(s, &cv, TRUE, TRUE);
break;
case DOWN:
@@ -146,7 +146,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_MUTED;
}
- pa_sink_set_volume(s, &cv);
+ pa_sink_set_volume(s, &cv, TRUE, TRUE);
break;
case MUTE:
diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c
index aa6832b..a379923 100644
--- a/src/modules/module-mmkbd-evdev.c
+++ b/src/modules/module-mmkbd-evdev.c
@@ -126,7 +126,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_NORM;
}
- pa_sink_set_volume(s, &cv);
+ pa_sink_set_volume(s, &cv, TRUE, TRUE);
break;
case DOWN:
@@ -137,7 +137,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_MUTED;
}
- pa_sink_set_volume(s, &cv);
+ pa_sink_set_volume(s, &cv, TRUE, TRUE);
break;
case MUTE_TOGGLE:
diff --git a/src/modules/module-position-event-sounds.c b/src/modules/module-position-event-sounds.c
index 90e693a..e75b1c5 100644
--- a/src/modules/module-position-event-sounds.c
+++ b/src/modules/module-position-event-sounds.c
@@ -101,23 +101,23 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *core, pa_sink_i
pa_log_debug("Positioning event sound '%s' at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f);
- if (!data->volume_is_set) {
- pa_cvolume_reset(&data->volume, data->sample_spec.channels);
- data->volume_is_set = TRUE;
+ if (!data->virtual_volume_is_set) {
+ pa_cvolume_reset(&data->virtual_volume, data->sample_spec.channels);
+ data->virtual_volume_is_set = TRUE;
}
for (c = 0; c < data->sample_spec.channels; c++) {
if (is_left(data->channel_map.map[c]))
- data->volume.values[c] =
- pa_sw_volume_multiply(data->volume.values[c], (pa_volume_t) (PA_VOLUME_NORM * (1.0 - f)));
+ data->virtual_volume.values[c] =
+ pa_sw_volume_multiply(data->virtual_volume.values[c], (pa_volume_t) (PA_VOLUME_NORM * (1.0 - f)));
if (is_right(data->channel_map.map[c]))
- data->volume.values[c] =
- pa_sw_volume_multiply(data->volume.values[c], (pa_volume_t) (PA_VOLUME_NORM * f));
+ data->virtual_volume.values[c] =
+ pa_sw_volume_multiply(data->virtual_volume.values[c], (pa_volume_t) (PA_VOLUME_NORM * f));
}
- pa_log_debug("Final volume %s.", pa_cvolume_snprint(t, sizeof(t), &data->volume));
+ pa_log_debug("Final volume %s.", pa_cvolume_snprint(t, sizeof(t), &data->virtual_volume));
return PA_HOOK_OK;
}
diff --git a/src/modules/module-raop-sink.c b/src/modules/module-raop-sink.c
index bb93ca8..02ef2aa 100644
--- a/src/modules/module-raop-sink.c
+++ b/src/modules/module-raop-sink.c
@@ -255,20 +255,17 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
return pa_sink_process_msg(o, code, data, offset, chunk);
}
-static int sink_get_volume_cb(pa_sink *s) {
+static void sink_get_volume_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int i;
pa_assert(u);
- for (i = 0; i < s->sample_spec.channels; i++) {
- s->volume.values[i] = u->volume;
- }
-
- return 0;
+ for (i = 0; i < s->sample_spec.channels; i++)
+ s->virtual_volume.values[i] = u->volume;
}
-static int sink_set_volume_cb(pa_sink *s) {
+static void sink_set_volume_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int rv;
@@ -276,39 +273,34 @@ static int sink_set_volume_cb(pa_sink *s) {
/* If we're muted, we fake it */
if (u->muted)
- return 0;
+ return;
pa_assert(s->sample_spec.channels > 0);
/* Avoid pointless volume sets */
- if (u->volume == s->volume.values[0])
- return 0;
+ if (u->volume == s->virtual_volume.values[0])
+ return;
- rv = pa_raop_client_set_volume(u->raop, s->volume.values[0]);
+ rv = pa_raop_client_set_volume(u->raop, s->virtual_volume.values[0]);
if (0 == rv)
- u->volume = s->volume.values[0];
-
- return rv;
+ u->volume = s->virtual_volume.values[0];
}
-static int sink_get_mute_cb(pa_sink *s) {
+static void sink_get_mute_cb(pa_sink *s) {
struct userdata *u = s->userdata;
pa_assert(u);
s->muted = u->muted;
- return 0;
}
-static int sink_set_mute_cb(pa_sink *s) {
+static void sink_set_mute_cb(pa_sink *s) {
struct userdata *u = s->userdata;
- int rv;
pa_assert(u);
- rv = pa_raop_client_set_volume(u->raop, (s->muted ? PA_VOLUME_MUTED : u->volume));
+ pa_raop_client_set_volume(u->raop, (s->muted ? PA_VOLUME_MUTED : u->volume));
u->muted = s->muted;
- return rv;
}
static void thread_func(void *userdata) {
diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
index 734b2c5..464ff2d 100644
--- a/src/modules/module-stream-restore.c
+++ b/src/modules/module-stream-restore.c
@@ -334,9 +334,9 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
if (u->restore_volume) {
- if (!new_data->volume_is_set) {
+ if (!new_data->virtual_volume_is_set) {
pa_log_info("Restoring volume for sink input %s.", name);
- pa_sink_input_new_data_set_volume(new_data, pa_cvolume_remap(&e->volume, &e->channel_map, &new_data->channel_map));
+ pa_sink_input_new_data_set_virtual_volume(new_data, pa_cvolume_remap(&e->volume, &e->channel_map, &new_data->channel_map));
} else
pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
}
diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c
index 61b9516..5c7a6e5 100644
--- a/src/modules/module-tunnel.c
+++ b/src/modules/module-tunnel.c
@@ -1056,10 +1056,10 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag
pa_assert(u->sink);
if ((u->version < 11 || !!mute == !!u->sink->muted) &&
- pa_cvolume_equal(&volume, &u->sink->volume))
+ pa_cvolume_equal(&volume, &u->sink->virtual_volume))
return;
- memcpy(&u->sink->volume, &volume, sizeof(pa_cvolume));
+ memcpy(&u->sink->virtual_volume, &volume, sizeof(pa_cvolume));
if (u->version >= 11)
u->sink->muted = !!mute;
@@ -1621,7 +1621,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata
#ifdef TUNNEL_SINK
/* Called from main context */
-static int sink_set_volume(pa_sink *sink) {
+static void sink_set_volume(pa_sink *sink) {
struct userdata *u;
pa_tagstruct *t;
uint32_t tag;
@@ -1634,14 +1634,12 @@ static int sink_set_volume(pa_sink *sink) {
pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME);
pa_tagstruct_putu32(t, tag = u->ctag++);
pa_tagstruct_putu32(t, u->device_index);
- pa_tagstruct_put_cvolume(t, &sink->volume);
+ pa_tagstruct_put_cvolume(t, &sink->virtual_volume);
pa_pstream_send_tagstruct(u->pstream, t);
-
- return 0;
}
/* Called from main context */
-static int sink_set_mute(pa_sink *sink) {
+static void sink_set_mute(pa_sink *sink) {
struct userdata *u;
pa_tagstruct *t;
uint32_t tag;
@@ -1651,7 +1649,7 @@ static int sink_set_mute(pa_sink *sink) {
pa_assert(u);
if (u->version < 11)
- return -1;
+ return;
t = pa_tagstruct_new(NULL, 0);
pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_MUTE);
@@ -1659,8 +1657,6 @@ static int sink_set_mute(pa_sink *sink) {
pa_tagstruct_putu32(t, u->device_index);
pa_tagstruct_put_boolean(t, !!sink->muted);
pa_pstream_send_tagstruct(u->pstream, t);
-
- return 0;
}
#endif
diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c
index bdfd381..e32552c 100644
--- a/src/modules/module-volume-restore.c
+++ b/src/modules/module-volume-restore.c
@@ -443,7 +443,7 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
if (r->volume_is_set && data->sample_spec.channels == r->volume.channels) {
pa_log_info("Restoring volume for <%s>", r->name);
- pa_sink_input_new_data_set_volume(data, &r->volume);
+ pa_sink_input_new_data_set_virtual_volume(data, &r->volume);
}
}
diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c
index 7271a08..eac0c8e 100644
--- a/src/modules/oss/module-oss.c
+++ b/src/modules/oss/module-oss.c
@@ -443,7 +443,6 @@ static pa_usec_t io_sink_get_latency(struct userdata *u) {
return r;
}
-
static pa_usec_t io_source_get_latency(struct userdata *u) {
pa_usec_t r = 0;
@@ -527,9 +526,6 @@ static int suspend(struct userdata *u) {
return 0;
}
-static int sink_get_volume(pa_sink *s);
-static int source_get_volume(pa_source *s);
-
static int unsuspend(struct userdata *u) {
int m;
pa_sample_spec ss, *ss_original;
@@ -620,10 +616,10 @@ static int unsuspend(struct userdata *u) {
build_pollfd(u);
- if (u->sink && u->sink->get_volume)
- u->sink->get_volume(u->sink);
- if (u->source && u->source->get_volume)
- u->source->get_volume(u->source);
+ if (u->sink)
+ pa_sink_get_volume(u->sink, TRUE);
+ if (u->source)
+ pa_source_get_volume(u->source, TRUE);
pa_log_info("Resumed successfully...");
@@ -798,84 +794,76 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
return ret;
}
-static int sink_get_volume(pa_sink *s) {
+static void sink_get_volume(pa_sink *s) {
struct userdata *u;
- int r;
pa_assert_se(u = s->userdata);
pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
if (u->mixer_devmask & SOUND_MASK_VOLUME)
- if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->volume)) >= 0)
- return r;
+ if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->virtual_volume) >= 0)
+ return;
if (u->mixer_devmask & SOUND_MASK_PCM)
- if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->volume)) >= 0)
- return r;
+ if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->virtual_volume) >= 0)
+ return;
pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
- return -1;
}
-static int sink_set_volume(pa_sink *s) {
+static void sink_set_volume(pa_sink *s) {
struct userdata *u;
- int r;
pa_assert_se(u = s->userdata);
pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
if (u->mixer_devmask & SOUND_MASK_VOLUME)
- if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->volume)) >= 0)
- return r;
+ if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->virtual_volume) >= 0)
+ return;
if (u->mixer_devmask & SOUND_MASK_PCM)
- if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->volume)) >= 0)
- return r;
+ if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->virtual_volume) >= 0)
+ return;
pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
- return -1;
}
-static int source_get_volume(pa_source *s) {
+static void source_get_volume(pa_source *s) {
struct userdata *u;
- int r;
pa_assert_se(u = s->userdata);
pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
if (u->mixer_devmask & SOUND_MASK_IGAIN)
- if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->volume)) >= 0)
- return r;
+ if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->virtual_volume) >= 0)
+ return;
if (u->mixer_devmask & SOUND_MASK_RECLEV)
- if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->volume)) >= 0)
- return r;
+ if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->virtual_volume) >= 0)
+ return;
pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
- return -1;
}
-static int source_set_volume(pa_source *s) {
+static void source_set_volume(pa_source *s) {
struct userdata *u;
- int r;
pa_assert_se(u = s->userdata);
pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
if (u->mixer_devmask & SOUND_MASK_IGAIN)
- if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->volume)) >= 0)
- return r;
+ if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->virtual_volume) >= 0)
+ return;
if (u->mixer_devmask & SOUND_MASK_RECLEV)
- if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->volume)) >= 0)
- return r;
+ if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->virtual_volume) >= 0)
+ return;
pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
- return -1;
}
static void thread_func(void *userdata) {
@@ -1417,6 +1405,7 @@ int pa__init(pa_module*m) {
u->sink->flags |= PA_SINK_HW_VOLUME_CTRL;
u->sink->get_volume = sink_get_volume;
u->sink->set_volume = sink_set_volume;
+ u->sink->n_volume_steps = 101;
do_close = FALSE;
}
@@ -1425,6 +1414,7 @@ int pa__init(pa_module*m) {
u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL;
u->source->get_volume = source_get_volume;
u->source->set_volume = source_set_volume;
+ u->source->n_volume_steps = 101;
do_close = FALSE;
}
}
diff --git a/src/pulse/def.h b/src/pulse/def.h
index c2c90e9..7517a7a 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -600,9 +600,13 @@ typedef enum pa_sink_flags {
PA_SINK_HW_MUTE_CTRL = 0x0010U,
/**< Supports hardware mute control \since 0.9.11 */
- PA_SINK_DECIBEL_VOLUME = 0x0020U
+ PA_SINK_DECIBEL_VOLUME = 0x0020U,
/**< Volume can be translated to dB with pa_sw_volume_to_dB()
* \since 0.9.11 */
+
+ PA_SINK_FLAT_VOLUME = 0x0040U
+ /**< This sink is in flat volume mode, i.e. always the maximum of
+ * the volume of all connected inputs. \since 0.9.15 */
} pa_sink_flags_t;
/** \cond fulldocs */
@@ -612,6 +616,7 @@ typedef enum pa_sink_flags {
#define PA_SINK_NETWORK PA_SINK_NETWORK
#define PA_SINK_HW_MUTE_CTRL PA_SINK_HW_MUTE_CTRL
#define PA_SINK_DECIBEL_VOLUME PA_SINK_DECIBEL_VOLUME
+#define PA_SINK_FLAT_VOLUME PA_SINK_FLAT_VOLUME
/** \endcond */
/** Sink state. \since 0.9.15 */
diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
index c5c9678..1d50939 100644
--- a/src/pulse/introspect.c
+++ b/src/pulse/introspect.c
@@ -159,6 +159,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u
memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new();
i.base_volume = PA_VOLUME_NORM;
+ i.n_volume_steps = PA_VOLUME_NORM+1;
mute = FALSE;
state = PA_SINK_INVALID_STATE;
@@ -180,7 +181,8 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u
pa_tagstruct_get_usec(t, &i.configured_latency) < 0)) ||
(o->context->version >= 15 &&
(pa_tagstruct_get_volume(t, &i.base_volume) < 0 ||
- pa_tagstruct_getu32(t, &state) < 0))) {
+ pa_tagstruct_getu32(t, &state) < 0 ||
+ pa_tagstruct_getu32(t, &i.n_volume_steps) < 0))) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
pa_proplist_free(i.proplist);
@@ -288,6 +290,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new();
i.base_volume = PA_VOLUME_NORM;
+ i.n_volume_steps = PA_VOLUME_NORM+1;
mute = FALSE;
state = PA_SOURCE_INVALID_STATE;
@@ -309,7 +312,8 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
pa_tagstruct_get_usec(t, &i.configured_latency) < 0)) ||
(o->context->version >= 15 &&
(pa_tagstruct_get_volume(t, &i.base_volume) < 0 ||
- pa_tagstruct_getu32(t, &state) < 0))) {
+ pa_tagstruct_getu32(t, &state) < 0 ||
+ pa_tagstruct_getu32(t, &i.n_volume_steps) < 0))) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
pa_proplist_free(i.proplist);
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index d8a28ff..badc787 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -214,6 +214,7 @@ typedef struct pa_sink_info {
pa_usec_t configured_latency; /**< The latency this device has been configured to. \since 0.9.11 */
pa_volume_t base_volume; /**< Some kind of "base" volume that refers to unamplified/unattenuated volume in the context of the output device. \since 0.9.15 */
pa_sink_state_t state; /**< State \since 0.9.15 */
+ uint32_t n_volume_steps; /**< Number of volume steps for sinks which do not support arbitrary volumes. \since 0.9.15 */
} pa_sink_info;
/** Callback prototype for pa_context_get_sink_info_by_name() and friends */
@@ -269,8 +270,9 @@ typedef struct pa_source_info {
pa_source_flags_t flags; /**< Flags */
pa_proplist *proplist; /**< Property list \since 0.9.11 */
pa_usec_t configured_latency; /**< The latency this device has been configured to. \since 0.9.11 */
- pa_volume_t base_volume; /**< Some kind of "base" volume that refers to unamplified/unattenuated volume in the context of the input device. \since 0.9.15 */
- pa_source_state_t state; /**< State \since 0.9.15 */
+ pa_volume_t base_volume; /**< Some kind of "base" volume that refers to unamplified/unattenuated volume in the context of the input device. \since 0.9.15 */
+ pa_source_state_t state; /**< State \since 0.9.15 */
+ uint32_t n_volume_steps; /**< Number of volume steps for sources which do not support arbitrary volumes. \since 0.9.15 */
} pa_source_info;
/** Callback prototype for pa_context_get_source_info_by_name() and friends */
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index da3ef1e..b93f24f 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -518,7 +518,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
}
pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume);
- pa_sink_set_volume(sink, &cvolume);
+ pa_sink_set_volume(sink, &cvolume, TRUE, TRUE);
return 0;
}
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index c74ca5d..647fc1b 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -232,11 +232,12 @@ char *pa_sink_list_to_string(pa_core *c) {
" %c index: %u\n"
"\tname: <%s>\n"
"\tdriver: <%s>\n"
- "\tflags: %s%s%s%s%s%s\n"
+ "\tflags: %s%s%s%s%s%s%s\n"
"\tstate: %s\n"
"\tvolume: %s%s%s\n"
"\t balance %0.2f\n"
"\tbase volume: %s%s%s\n"
+ "\tvolume steps: %u\n"
"\tmuted: %s\n"
"\tcurrent latency: %0.2f ms\n"
"\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n"
@@ -257,6 +258,7 @@ char *pa_sink_list_to_string(pa_core *c) {
sink->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
sink->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
sink->flags & PA_SINK_LATENCY ? "LATENCY " : "",
+ sink->flags & PA_SINK_FLAT_VOLUME ? "FLAT_VOLUME" : "",
sink_state_to_string(pa_sink_get_state(sink)),
pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)),
sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
@@ -265,6 +267,7 @@ char *pa_sink_list_to_string(pa_core *c) {
pa_volume_snprint(v, sizeof(v), sink->base_volume),
sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), sink->base_volume) : "",
+ sink->n_volume_steps,
pa_yes_no(pa_sink_get_mute(sink, FALSE)),
(double) pa_sink_get_latency(sink) / (double) PA_USEC_PER_MSEC,
(double) pa_sink_get_requested_latency(sink) / (double) PA_USEC_PER_MSEC,
@@ -275,7 +278,7 @@ char *pa_sink_list_to_string(pa_core *c) {
sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map),
- cmn ? "\n\t " : "",
+ cmn ? "\n\t " : "",
cmn ? cmn : "",
pa_sink_used_by(sink),
pa_sink_linked_by(sink));
@@ -327,6 +330,7 @@ char *pa_source_list_to_string(pa_core *c) {
"\tvolume: %s%s%s\n"
"\t balance %0.2f\n"
"\tbase volume: %s%s%s\n"
+ "\tvolume steps: %u\n"
"\tmuted: %s\n"
"\tcurrent latency: %0.2f ms\n"
"\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n"
@@ -353,6 +357,7 @@ char *pa_source_list_to_string(pa_core *c) {
pa_volume_snprint(v, sizeof(v), source->base_volume),
source->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
source->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), source->base_volume) : "",
+ source->n_volume_steps,
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,
@@ -361,7 +366,7 @@ char *pa_source_list_to_string(pa_core *c) {
(unsigned long) pa_source_get_max_rewind(source) / 1024,
pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map),
- cmn ? "\n\t " : "",
+ cmn ? "\n\t " : "",
cmn ? cmn : "",
pa_source_used_by(source),
pa_source_linked_by(source));
@@ -440,7 +445,7 @@ char *pa_source_output_list_to_string(pa_core *c) {
clt,
pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map),
- cmn ? "\n\t " : "",
+ cmn ? "\n\t " : "",
cmn ? cmn : "",
pa_resample_method_to_string(pa_source_output_get_resample_method(o)));
if (o->module)
@@ -525,7 +530,7 @@ char *pa_sink_input_list_to_string(pa_core *c) {
clt,
pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
- cmn ? "\n\t " : "",
+ cmn ? "\n\t " : "",
cmn ? cmn : "",
pa_resample_method_to_string(pa_sink_input_get_resample_method(i)));
@@ -584,7 +589,7 @@ char *pa_scache_list_to_string(pa_core *c) {
e->index,
ss,
cm,
- cmn ? "\n\t " : "",
+ cmn ? "\n\t " : "",
cmn ? cmn : "",
(long unsigned)(e->memchunk.memblock ? e->memchunk.length : 0),
l,
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index c6e96c1..381a677 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -127,6 +127,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, pa_bool_t shared, size_t shm_size) {
c->exit_idle_time = -1;
c->scache_idle_time = 20;
+ c->flat_volumes = TRUE;
c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3;
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index ffac6d3..e33a245 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -55,7 +55,6 @@ typedef enum pa_core_hook {
PA_CORE_HOOK_SINK_UNLINK_POST,
PA_CORE_HOOK_SINK_STATE_CHANGED,
PA_CORE_HOOK_SINK_PROPLIST_CHANGED,
- PA_CORE_HOOK_SINK_SET_VOLUME,
PA_CORE_HOOK_SOURCE_NEW,
PA_CORE_HOOK_SOURCE_FIXATE,
PA_CORE_HOOK_SOURCE_PUT,
@@ -129,6 +128,7 @@ struct pa_core {
pa_silence_cache silence_cache;
int exit_idle_time, scache_idle_time;
+ pa_bool_t flat_volumes;
pa_time_event *exit_event;
diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c
index 758c0de..eac21de 100644
--- a/src/pulsecore/play-memblockq.c
+++ b/src/pulsecore/play-memblockq.c
@@ -197,7 +197,7 @@ pa_sink_input* pa_memblockq_sink_input_new(
data.driver = __FILE__;
pa_sink_input_new_data_set_sample_spec(&data, ss);
pa_sink_input_new_data_set_channel_map(&data, map);
- pa_sink_input_new_data_set_volume(&data, volume);
+ pa_sink_input_new_data_set_virtual_volume(&data, volume);
pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
u->sink_input = pa_sink_input_new(sink->core, &data, 0);
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 3896dff..80edb20 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -1012,7 +1012,7 @@ static playback_stream* playback_stream_new(
pa_sink_input_new_data_set_sample_spec(&data, ss);
pa_sink_input_new_data_set_channel_map(&data, map);
if (volume)
- pa_sink_input_new_data_set_volume(&data, volume);
+ pa_sink_input_new_data_set_virtual_volume(&data, volume);
if (muted_set)
pa_sink_input_new_data_set_muted(&data, muted);
data.sync_base = ssync ? ssync->sink_input : NULL;
@@ -2691,6 +2691,7 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin
if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
pa_log_error("Internal sink state is invalid.");
pa_tagstruct_putu32(t, pa_sink_get_state(sink));
+ pa_tagstruct_putu32(t, sink->n_volume_steps);
}
}
@@ -2729,6 +2730,7 @@ static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s
if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
pa_log_error("Internal source state is invalid.");
pa_tagstruct_putu32(t, pa_source_get_state(source));
+ pa_tagstruct_putu32(t, source->n_volume_steps);
}
}
@@ -3164,7 +3166,7 @@ static void command_set_volume(
CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
if (sink)
- pa_sink_set_volume(sink, &volume);
+ pa_sink_set_volume(sink, &volume, TRUE, TRUE);
else if (source)
pa_source_set_volume(source, &volume);
else if (si)
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index d1ffb0f..8b76df0 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -72,11 +72,18 @@ void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const
data->channel_map = *map;
}
-void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
+void pa_sink_input_new_data_set_soft_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
pa_assert(data);
- if ((data->volume_is_set = !!volume))
- data->volume = data->virtual_volume = *volume;
+ if ((data->soft_volume_is_set = !!volume))
+ data->soft_volume = *volume;
+}
+
+void pa_sink_input_new_data_set_virtual_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
+ pa_assert(data);
+
+ if ((data->virtual_volume_is_set = !!volume))
+ data->virtual_volume = *volume;
}
void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute) {
@@ -153,17 +160,34 @@ pa_sink_input* pa_sink_input_new(
pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
pa_return_null_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec));
- if (!data->volume_is_set) {
- pa_cvolume_reset(&data->volume, data->sample_spec.channels);
- pa_cvolume_reset(&data->virtual_volume, data->sample_spec.channels);
- }
+ if (!data->virtual_volume_is_set) {
- pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
- pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));
+ if (data->sink->flags & PA_SINK_FLAT_VOLUME) {
+ data->virtual_volume = data->sink->virtual_volume;
+ pa_cvolume_remap(&data->virtual_volume, &data->sink->channel_map, &data->channel_map);
+ } else
+ pa_cvolume_reset(&data->virtual_volume, data->sample_spec.channels);
+
+ } else if (!data->virtual_volume_is_absolute) {
+
+ /* When the 'absolute' bool is set then we'll treat the volume
+ * as relative to the sink volume even in flat volume mode */
+ if (data->sink->flags & PA_SINK_FLAT_VOLUME) {
+ pa_cvolume t = data->sink->virtual_volume;
+ pa_cvolume_remap(&t, &data->sink->channel_map, &data->channel_map);
+ pa_sw_cvolume_multiply(&data->virtual_volume, &data->virtual_volume, &t);
+ }
+ }
pa_return_null_if_fail(pa_cvolume_valid(&data->virtual_volume));
pa_return_null_if_fail(pa_cvolume_compatible(&data->virtual_volume, &data->sample_spec));
+ if (!data->soft_volume_is_set)
+ data->soft_volume = data->virtual_volume;
+
+ pa_return_null_if_fail(pa_cvolume_valid(&data->soft_volume));
+ pa_return_null_if_fail(pa_cvolume_compatible(&data->soft_volume, &data->sample_spec));
+
if (!data->muted_is_set)
data->muted = FALSE;
@@ -184,7 +208,8 @@ pa_sink_input* pa_sink_input_new(
pa_assert(pa_channel_map_valid(&data->channel_map));
/* Due to the fixing of the sample spec the volume might not match anymore */
- pa_cvolume_remap(&data->volume, &original_cm, &data->channel_map);
+ pa_cvolume_remap(&data->soft_volume, &original_cm, &data->channel_map);
+ pa_cvolume_remap(&data->virtual_volume, &original_cm, &data->channel_map);
if (data->resample_method == PA_RESAMPLER_INVALID)
data->resample_method = core->resample_method;
@@ -239,7 +264,7 @@ pa_sink_input* pa_sink_input_new(
i->channel_map = data->channel_map;
i->virtual_volume = data->virtual_volume;
- i->volume = data->volume;
+ i->soft_volume = data->soft_volume;
i->muted = data->muted;
@@ -263,7 +288,7 @@ pa_sink_input* pa_sink_input_new(
pa_atomic_store(&i->thread_info.drained, 1);
i->thread_info.sample_spec = i->sample_spec;
i->thread_info.resampler = resampler;
- i->thread_info.volume = i->volume;
+ i->thread_info.soft_volume = i->soft_volume;
i->thread_info.muted = i->muted;
i->thread_info.requested_sink_latency = (pa_usec_t) -1;
i->thread_info.rewrite_nbytes = 0;
@@ -395,9 +420,17 @@ void pa_sink_input_unlink(pa_sink_input *i) {
update_n_corked(i, PA_SINK_INPUT_UNLINKED);
i->state = PA_SINK_INPUT_UNLINKED;
- if (linked && i->sink)
+ if (linked && i->sink) {
+ /* We might need to update the sink's volume if we are in flat volume mode. */
+ if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
+ pa_cvolume new_volume;
+ pa_sink_update_flat_volume(i->sink, &new_volume);
+ pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+ }
+
if (i->sink->asyncmsgq)
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL) == 0);
+ }
reset_callbacks(i);
@@ -459,7 +492,7 @@ void pa_sink_input_put(pa_sink_input *i) {
pa_assert(i->process_rewind);
pa_assert(i->kill);
- i->thread_info.volume = i->volume;
+ i->thread_info.soft_volume = i->soft_volume;
i->thread_info.muted = i->muted;
state = i->flags & PA_SINK_INPUT_START_CORKED ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING;
@@ -467,6 +500,13 @@ void pa_sink_input_put(pa_sink_input *i) {
update_n_corked(i, state);
i->state = state;
+ /* We might need to update the sink's volume if we are in flat volume mode. */
+ if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
+ pa_cvolume new_volume;
+ pa_sink_update_flat_volume(i->sink, &new_volume);
+ pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+ }
+
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL) == 0);
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index);
@@ -552,7 +592,7 @@ int pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa
* it after and leave it for the sink code */
do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map);
- volume_is_norm = pa_cvolume_is_norm(&i->thread_info.volume) && !i->thread_info.muted;
+ volume_is_norm = pa_cvolume_is_norm(&i->thread_info.soft_volume) && !i->thread_info.muted;
while (!pa_memblockq_is_readable(i->thread_info.render_memblockq)) {
pa_memchunk tchunk;
@@ -598,7 +638,7 @@ int pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa
if (i->thread_info.muted)
pa_silence_memchunk(&wchunk, &i->thread_info.sample_spec);
else
- pa_volume_memchunk(&wchunk, &i->thread_info.sample_spec, &i->thread_info.volume);
+ pa_volume_memchunk(&wchunk, &i->thread_info.sample_spec, &i->thread_info.soft_volume);
}
if (!i->thread_info.resampler)
@@ -644,7 +684,7 @@ int pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa
/* We've both the same channel map, so let's have the sink do the adjustment for us*/
pa_cvolume_mute(volume, i->sink->sample_spec.channels);
else
- *volume = i->thread_info.volume;
+ *volume = i->thread_info.soft_volume;
return 0;
}
@@ -816,34 +856,41 @@ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) {
/* Called from main context */
void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) {
- pa_sink_input_set_volume_data data;
-
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
pa_assert(volume);
pa_assert(pa_cvolume_valid(volume));
pa_assert(pa_cvolume_compatible(volume, &i->sample_spec));
- data.sink_input = i;
- data.virtual_volume = *volume;
- data.volume = *volume;
+ if (pa_cvolume_equal(volume, &i->virtual_volume))
+ return;
- /* If you change something here, consider looking into
- * module-flat-volume.c as well since it uses very similar
- * code. */
+ i->virtual_volume = *volume;
- if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], &data) < 0)
- return;
+ if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
+ pa_cvolume new_volume;
- if (!pa_cvolume_equal(&i->volume, &data.volume)) {
- i->volume = data.volume;
- pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, &data.volume, 0, NULL) == 0);
- }
+ /* We are in flat volume mode, so let's update all sink input
+ * volumes and update the flat volume of the sink */
- if (!pa_cvolume_equal(&i->virtual_volume, &data.virtual_volume)) {
- i->virtual_volume = data.virtual_volume;
- pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ pa_sink_update_flat_volume(i->sink, &new_volume);
+ pa_sink_set_volume(i->sink, &new_volume, FALSE, TRUE);
+
+ } else {
+
+ /* OK, we are in normal volume mode. The volume only affects
+ * ourselves */
+
+ i->soft_volume = *volume;
+
+ /* Hooks have the ability to play games with i->soft_volume */
+ pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i);
+
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
}
+
+ /* The virtual volume changed, let's tell people so */
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
}
/* Called from main context */
@@ -865,7 +912,7 @@ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute) {
i->muted = mute;
- pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), 0, NULL, NULL);
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE, NULL, 0, NULL) == 0);
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
}
@@ -1013,15 +1060,22 @@ int pa_sink_input_start_move(pa_sink_input *i) {
}
pa_assert(pa_idxset_isempty(i->direct_outputs));
- pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0);
+ pa_idxset_remove_by_data(i->sink->inputs, i, NULL);
if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED)
pa_assert_se(i->sink->n_corked-- >= 1);
- pa_idxset_remove_by_data(i->sink->inputs, i, NULL);
- i->sink = NULL;
+ /* We might need to update the sink's volume if we are in flat volume mode. */
+ if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
+ pa_cvolume new_volume;
+ pa_sink_update_flat_volume(i->sink, &new_volume);
+ pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+ }
+
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0);
- pa_sink_update_status(origin);
+ pa_sink_update_status(i->sink);
+ i->sink = NULL;
return 0;
}
@@ -1092,6 +1146,14 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest) {
}
pa_sink_update_status(dest);
+
+ /* We might need to update the sink's volume if we are in flat volume mode. */
+ if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
+ pa_cvolume new_volume;
+ pa_sink_update_flat_volume(i->sink, &new_volume);
+ pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+ }
+
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0);
pa_log_debug("Successfully moved sink input %i to %s.", i->index, dest->name);
@@ -1176,14 +1238,18 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
switch (code) {
- case PA_SINK_INPUT_MESSAGE_SET_VOLUME:
- i->thread_info.volume = *((pa_cvolume*) userdata);
- pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
+ case PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME:
+ if (!pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume)) {
+ i->thread_info.soft_volume = i->soft_volume;
+ pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
+ }
return 0;
- case PA_SINK_INPUT_MESSAGE_SET_MUTE:
- i->thread_info.muted = PA_PTR_TO_UINT(userdata);
- pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
+ case PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE:
+ if (i->thread_info.muted != i->muted) {
+ i->thread_info.muted = i->muted;
+ pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
+ }
return 0;
case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 66ec613..5bf38de 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -90,9 +90,7 @@ struct pa_sink_input {
pa_sink_input *sync_prev, *sync_next;
- pa_cvolume virtual_volume;
-
- pa_cvolume volume;
+ pa_cvolume virtual_volume, soft_volume;
pa_bool_t muted;
pa_resample_method_t requested_resample_method, actual_resample_method;
@@ -170,7 +168,15 @@ struct pa_sink_input {
pa_sink_input_state_t state;
pa_atomic_t drained;
- pa_bool_t attached; /* True only between ->attach() and ->detach() calls */
+ pa_cvolume soft_volume;
+ pa_bool_t muted:1;
+
+ pa_bool_t attached:1; /* True only between ->attach() and ->detach() calls */
+
+ /* 0: rewrite nothing, (size_t) -1: rewrite everything, otherwise how many bytes to rewrite */
+ pa_bool_t rewrite_flush:1, dont_rewind_render:1;
+ size_t rewrite_nbytes;
+ uint64_t underrun_for, playing_for;
pa_sample_spec sample_spec;
@@ -179,16 +185,8 @@ struct pa_sink_input {
/* We maintain a history of resampled audio data here. */
pa_memblockq *render_memblockq;
- /* 0: rewrite nothing, (size_t) -1: rewrite everything, otherwise how many bytes to rewrite */
- size_t rewrite_nbytes;
- pa_bool_t rewrite_flush, dont_rewind_render;
- uint64_t underrun_for, playing_for;
-
pa_sink_input *sync_prev, *sync_next;
- pa_cvolume volume;
- pa_bool_t muted;
-
/* The requested latency for the sink */
pa_usec_t requested_sink_latency;
@@ -202,8 +200,8 @@ PA_DECLARE_CLASS(pa_sink_input);
#define PA_SINK_INPUT(o) pa_sink_input_cast(o)
enum {
- PA_SINK_INPUT_MESSAGE_SET_VOLUME,
- PA_SINK_INPUT_MESSAGE_SET_MUTE,
+ PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME,
+ PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE,
PA_SINK_INPUT_MESSAGE_GET_LATENCY,
PA_SINK_INPUT_MESSAGE_SET_RATE,
PA_SINK_INPUT_MESSAGE_SET_STATE,
@@ -228,30 +226,26 @@ typedef struct pa_sink_input_new_data {
pa_sample_spec sample_spec;
pa_channel_map channel_map;
- pa_cvolume virtual_volume;
-
- pa_cvolume volume;
+ pa_cvolume virtual_volume, soft_volume;
pa_bool_t muted:1;
pa_bool_t sample_spec_is_set:1;
pa_bool_t channel_map_is_set:1;
- pa_bool_t volume_is_set:1;
+
+ pa_bool_t virtual_volume_is_set:1, soft_volume_is_set:1;
pa_bool_t muted_is_set:1;
+
+ pa_bool_t virtual_volume_is_absolute: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);
-void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume);
+void pa_sink_input_new_data_set_soft_volume(pa_sink_input_new_data *data, const pa_cvolume *volume);
+void pa_sink_input_new_data_set_virtual_volume(pa_sink_input_new_data *data, const pa_cvolume *volume);
void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute);
void pa_sink_input_new_data_done(pa_sink_input_new_data *data);
-typedef struct pa_sink_set_input_volume_data {
- pa_sink_input *sink_input;
- pa_cvolume virtual_volume;
- pa_cvolume volume;
-} pa_sink_input_set_volume_data;
-
/* To be called by the implementing module only */
pa_sink_input* pa_sink_input_new(
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 083dbaa..7735d3a 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -195,10 +195,10 @@ pa_sink* pa_sink_new(
s->inputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
- s->volume = data->volume;
+ s->virtual_volume = data->volume;
+ pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
s->base_volume = PA_VOLUME_NORM;
- s->virtual_volume = s->volume;
-
+ s->n_volume_steps = PA_VOLUME_NORM+1;
s->muted = data->muted;
s->refresh_volume = s->refresh_muted = FALSE;
@@ -216,8 +216,8 @@ pa_sink* pa_sink_new(
0);
s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
- pa_cvolume_reset(&s->thread_info.soft_volume, s->sample_spec.channels);
- s->thread_info.soft_muted = FALSE;
+ s->thread_info.soft_volume = s->soft_volume;
+ s->thread_info.soft_muted = s->muted;
s->thread_info.state = s->state;
s->thread_info.rewind_nbytes = 0;
s->thread_info.rewind_requested = FALSE;
@@ -335,10 +335,17 @@ void pa_sink_put(pa_sink* s) {
if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) {
s->flags |= PA_SINK_DECIBEL_VOLUME;
- s->thread_info.soft_volume = s->volume;
+ s->thread_info.soft_volume = s->soft_volume;
s->thread_info.soft_muted = s->muted;
}
+ if (s->flags & PA_SINK_DECIBEL_VOLUME)
+ s->n_volume_steps = PA_VOLUME_NORM+1;
+
+ if (s->core->flat_volumes)
+ if (s->flags & PA_SINK_DECIBEL_VOLUME)
+ s->flags |= PA_SINK_FLAT_VOLUME;
+
pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
pa_source_put(s->monitor_source);
@@ -911,9 +918,100 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) {
}
/* Called from main thread */
-void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) {
- pa_bool_t changed;
- pa_sink_set_volume_data data;
+void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
+ pa_sink_input *i;
+ uint32_t idx;
+
+ /* This is called whenever a sink input volume changes and we
+ * might need to fix up the sink volume accordingly. Please note
+ * that we don't actually update the sinks volume here, we only
+ * return how it needs to be updated. The caller should then call
+ * pa_sink_set_flat_volume().*/
+
+ pa_cvolume_mute(new_volume, s->channel_map.channels);
+
+ /* First let's determine the new maximum volume of all inputs
+ * connected to this sink */
+ for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
+ unsigned c;
+ pa_cvolume remapped_volume;
+
+ remapped_volume = i->virtual_volume;
+ pa_cvolume_remap(&remapped_volume, &i->channel_map, &s->channel_map);
+
+ for (c = 0; c < new_volume->channels; c++)
+ if (remapped_volume.values[c] > new_volume->values[c])
+ new_volume->values[c] = remapped_volume.values[c];
+ }
+
+ /* Then, let's update the soft volumes of all inputs connected
+ * to this sink */
+ for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
+ pa_cvolume remapped_new_volume;
+
+ remapped_new_volume = *new_volume;
+ pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
+ pa_sw_cvolume_divide(&i->soft_volume, &i->virtual_volume, &remapped_new_volume);
+
+ /* Hooks have the ability to play games with i->soft_volume */
+ pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i);
+
+ /* We don't issue PA_SINK_INPUT_MESSAGE_SET_VOLUME because
+ * we want the update to have atomically with the sink
+ * volume update, hence we do it within the
+ * pa_sink_set_flat_volume() call below*/
+ }
+}
+
+/* Called from main thread */
+void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) {
+ pa_sink_input *i;
+ uint32_t idx;
+
+ pa_sink_assert_ref(s);
+ pa_assert(PA_SINK_IS_LINKED(s->state));
+ pa_assert(old_volume);
+ pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+
+ /* This is called whenever the sink volume changes that is not
+ * caused by a sink input volume change. We need to fix up the
+ * sink input volumes accordingly */
+
+ for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
+ pa_cvolume remapped_old_volume, remapped_new_volume, fixed_volume;
+ unsigned c;
+
+ remapped_new_volume = s->virtual_volume;
+ pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
+
+ remapped_old_volume = *old_volume;
+ pa_cvolume_remap(&remapped_old_volume, &s->channel_map, &i->channel_map);
+
+ for (c = 0; c < i->sample_spec.channels; c++)
+
+ if (remapped_old_volume.values[c] == PA_VOLUME_MUTED)
+ fixed_volume.values[c] = PA_VOLUME_MUTED;
+ else
+ fixed_volume.values[c] = (pa_volume_t)
+ ((uint64_t) i->virtual_volume.values[c] *
+ (uint64_t) remapped_new_volume.values[c] /
+ (uint64_t) remapped_old_volume.values[c]);
+
+ fixed_volume.channels = i->virtual_volume.channels;
+
+ if (!pa_cvolume_equal(&fixed_volume, &i->virtual_volume)) {
+ i->virtual_volume = fixed_volume;
+
+ /* The virtual volume changed, let's tell people so */
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
+ }
+}
+
+/* Called from main thread */
+void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg) {
+ pa_cvolume old_virtual_volume;
+ pa_bool_t virtual_volume_changed;
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
@@ -921,39 +1019,45 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) {
pa_assert(pa_cvolume_valid(volume));
pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
- data.sink = s;
- data.virtual_volume = data.volume = *volume;
+ old_virtual_volume = s->virtual_volume;
+ s->virtual_volume = *volume;
+ virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
- changed = !pa_cvolume_equal(&data.virtual_volume, &s->virtual_volume) ||
- !pa_cvolume_equal(&data.volume, &s->volume);
+ /* Propagate this volume change back to the inputs */
+ if (virtual_volume_changed)
+ if (propagate && (s->flags & PA_SINK_FLAT_VOLUME))
+ pa_sink_propagate_flat_volume(s, &old_virtual_volume);
- if (changed) {
- if (pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_SET_VOLUME], &data) < 0)
- return;
+ if (s->set_volume) {
+ /* If we have a function set_volume(), then we do not apply a
+ * soft volume by default. However, set_volume() is apply one
+ * to s->soft_volume */
- changed = !pa_cvolume_equal(&data.virtual_volume, &s->virtual_volume); /* from client-side view */
- }
+ pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
+ s->set_volume(s);
- s->volume = data.volume;
- s->virtual_volume = data.virtual_volume;
+ } else
+ /* If we have no function set_volume(), then the soft volume
+ * becomes the virtual volume */
+ s->soft_volume = s->virtual_volume;
- if (s->set_volume && s->set_volume(s) < 0)
- s->set_volume = NULL;
+ /* This tells the sink that soft and/or virtual volume changed */
+ if (sendmsg)
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
- if (!s->set_volume)
- pa_sink_set_soft_volume(s, &s->volume);
-
- if (changed)
+ if (virtual_volume_changed)
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
-/* Called from main thread */
+/* Called from main thread. Only to be called by sink implementor */
void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
pa_sink_assert_ref(s);
pa_assert(volume);
+ s->soft_volume = *volume;
+
if (PA_SINK_IS_LINKED(s->state))
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, volume, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
else
s->thread_info.soft_volume = *volume;
}
@@ -961,21 +1065,22 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *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 || force_refresh) {
- struct pa_cvolume old_volume = s->virtual_volume;
+ struct pa_cvolume old_virtual_volume = s->virtual_volume;
- if (s->get_volume && s->get_volume(s) < 0)
- s->get_volume = NULL;
+ if (s->get_volume)
+ s->get_volume(s);
- if (!s->get_volume) {
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, &s->volume, 0, NULL);
- s->virtual_volume = s->volume;
- }
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
+
+ if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
+
+ if (s->flags & PA_SINK_FLAT_VOLUME)
+ pa_sink_propagate_flat_volume(s, &old_virtual_volume);
- if (!pa_cvolume_equal(&old_volume, &s->virtual_volume))
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ }
}
return &s->virtual_volume;
@@ -983,21 +1088,20 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
/* Called from main thread */
void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
- pa_bool_t changed;
+ pa_bool_t old_muted;
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
- changed = s->muted != mute;
+ old_muted = s->muted;
s->muted = mute;
- if (s->set_mute && s->set_mute(s) < 0)
- s->set_mute = NULL;
+ if (s->set_mute)
+ s->set_mute(s);
- if (!s->set_mute)
- pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), 0, NULL, NULL);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
- if (changed)
+ if (old_muted != s->muted)
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
@@ -1005,16 +1109,14 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
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 || force_refresh) {
pa_bool_t old_muted = s->muted;
- if (s->get_mute && s->get_mute(s) < 0)
- s->get_mute = NULL;
+ if (s->get_mute)
+ s->get_mute(s);
- if (!s->get_mute)
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &s->muted, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
if (old_muted != s->muted)
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
@@ -1138,6 +1240,22 @@ unsigned pa_sink_check_suspend(pa_sink *s) {
return ret;
}
+/* Called from the IO thread */
+static void sync_input_volumes_within_thread(pa_sink *s) {
+ pa_sink_input *i;
+ void *state = NULL;
+
+ pa_sink_assert_ref(s);
+
+ while ((i = PA_SINK_INPUT(pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))) {
+ if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
+ continue;
+
+ i->thread_info.soft_volume = i->soft_volume;
+ pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
+ }
+}
+
/* Called from IO thread, except when it is not */
int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
pa_sink *s = PA_SINK(o);
@@ -1192,7 +1310,9 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
* slow start, i.e. need some time to buffer client
* samples before beginning streaming. */
- return 0;
+ /* In flat volume mode we need to update the volume as
+ * well */
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
}
case PA_SINK_MESSAGE_REMOVE_INPUT: {
@@ -1233,7 +1353,9 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
pa_sink_invalidate_requested_latency(s);
pa_sink_request_rewind(s, (size_t) -1);
- return 0;
+ /* In flat volume mode we need to update the volume as
+ * well */
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
}
case PA_SINK_MESSAGE_START_MOVE: {
@@ -1279,7 +1401,9 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
pa_log_debug("Requesting rewind due to started move");
pa_sink_request_rewind(s, (size_t) -1);
- return 0;
+ /* In flat volume mode we need to update the volume as
+ * well */
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
}
case PA_SINK_MESSAGE_FINISH_MOVE: {
@@ -1323,27 +1447,36 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
pa_sink_request_rewind(s, nbytes);
}
- return 0;
+ /* In flat volume mode we need to update the volume as
+ * well */
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
}
case PA_SINK_MESSAGE_SET_VOLUME:
- s->thread_info.soft_volume = *((pa_cvolume*) userdata);
- pa_sink_request_rewind(s, (size_t) -1);
- return 0;
+ if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
+ s->thread_info.soft_volume = s->soft_volume;
+ pa_sink_request_rewind(s, (size_t) -1);
+ }
- case PA_SINK_MESSAGE_SET_MUTE:
- s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
+ if (s->flags & PA_SINK_FLAT_VOLUME)
+ sync_input_volumes_within_thread(s);
- pa_sink_request_rewind(s, (size_t) -1);
return 0;
case PA_SINK_MESSAGE_GET_VOLUME:
- *((pa_cvolume*) userdata) = s->thread_info.soft_volume;
+ return 0;
+
+ case PA_SINK_MESSAGE_SET_MUTE:
+
+ if (!s->thread_info.soft_muted != s->muted) {
+ s->thread_info.soft_muted = s->muted;
+ pa_sink_request_rewind(s, (size_t) -1);
+ }
+
return 0;
case PA_SINK_MESSAGE_GET_MUTE:
- *((pa_bool_t*) userdata) = s->thread_info.soft_muted;
return 0;
case PA_SINK_MESSAGE_SET_STATE:
@@ -1676,6 +1809,7 @@ void pa_sink_update_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t m
pa_source_update_latency_range(s->monitor_source, min_latency, max_latency);
}
+/* Called from main context */
size_t pa_sink_get_max_rewind(pa_sink *s) {
size_t r;
pa_sink_assert_ref(s);
@@ -1688,6 +1822,7 @@ size_t pa_sink_get_max_rewind(pa_sink *s) {
return r;
}
+/* Called from main context */
size_t pa_sink_get_max_request(pa_sink *s) {
size_t r;
pa_sink_assert_ref(s);
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index a30245d..b26ca77 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -71,11 +71,11 @@ struct pa_sink {
unsigned n_corked;
pa_source *monitor_source;
- pa_cvolume volume;
- pa_cvolume virtual_volume;
- pa_bool_t muted;
+ pa_volume_t base_volume; /* shall be constant */
+ unsigned n_volume_steps; /* shall be constant */
- pa_volume_t base_volume; /* shall be constant */
+ pa_cvolume virtual_volume, soft_volume;
+ pa_bool_t muted:1;
pa_bool_t refresh_volume:1;
pa_bool_t refresh_muted:1;
@@ -94,23 +94,23 @@ struct pa_sink {
* context. If this is NULL a PA_SINK_MESSAGE_GET_VOLUME message
* will be sent to the IO thread instead. If refresh_volume is
* FALSE neither this function is called nor a message is sent. */
- int (*get_volume)(pa_sink *s); /* may be NULL */
+ void (*get_volume)(pa_sink *s); /* may be NULL */
/* Called when the volume shall be changed. Called from main loop
* context. If this is NULL a PA_SINK_MESSAGE_SET_VOLUME message
* will be sent to the IO thread instead. */
- int (*set_volume)(pa_sink *s); /* dito */
+ void (*set_volume)(pa_sink *s); /* dito */
/* Called when the mute setting is queried. Called from main loop
* context. If this is NULL a PA_SINK_MESSAGE_GET_MUTE message
* will be sent to the IO thread instead. If refresh_mute is
* FALSE neither this function is called nor a message is sent.*/
- int (*get_mute)(pa_sink *s); /* dito */
+ void (*get_mute)(pa_sink *s); /* dito */
/* Called when the mute setting shall be changed. Called from main
* loop context. If this is NULL a PA_SINK_MESSAGE_SET_MUTE
* message will be sent to the IO thread instead. */
- int (*set_mute)(pa_sink *s); /* dito */
+ void (*set_mute)(pa_sink *s); /* dito */
/* Called when a rewind request is issued. Called from IO thread
* context. */
@@ -125,6 +125,7 @@ struct pa_sink {
struct {
pa_sink_state_t state;
pa_hashmap *inputs;
+
pa_cvolume soft_volume;
pa_bool_t soft_muted:1;
@@ -203,13 +204,7 @@ void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volum
void pa_sink_new_data_set_muted(pa_sink_new_data *data, pa_bool_t mute);
void pa_sink_new_data_done(pa_sink_new_data *data);
-typedef struct pa_sink_set_volume_data {
- pa_sink *sink;
- pa_cvolume volume;
- pa_cvolume virtual_volume;
-} pa_sink_set_volume_data;
-
-/* To be called exclusively by the sink driver, from main context */
+/*** To be called exclusively by the sink driver, from main context */
pa_sink* pa_sink_new(
pa_core *core,
@@ -228,7 +223,9 @@ void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_
void pa_sink_detach(pa_sink *s);
void pa_sink_attach(pa_sink *s);
-/* May be called by everyone, from main context */
+void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume);
+
+/**** May be called by everyone, from main context */
/* The returned value is supposed to be in the time domain of the sound card! */
pa_usec_t pa_sink_get_latency(pa_sink *s);
@@ -242,11 +239,13 @@ int pa_sink_update_status(pa_sink*s);
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);
-void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume);
+void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume);
+void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume);
+
+void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg);
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 force_refres);
+pa_bool_t pa_sink_get_mute(pa_sink *sink, pa_bool_t force_refresh);
pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p);
@@ -260,7 +259,7 @@ pa_queue *pa_sink_move_all_start(pa_sink *s);
void pa_sink_move_all_finish(pa_sink *s, pa_queue *q);
void pa_sink_move_all_fail(pa_queue *q);
-/* To be called exclusively by the sink driver, from IO context */
+/*** To be called exclusively by the sink driver, from IO context */
void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result);
void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result);
@@ -281,7 +280,7 @@ void pa_sink_set_max_request(pa_sink *s, size_t max_request);
void pa_sink_update_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency);
-/* To be called exclusively by sink input drivers, from IO context */
+/*** To be called exclusively by sink input drivers, from IO context */
void pa_sink_request_rewind(pa_sink*s, size_t nbytes);
diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c
index b78afca..1be421f 100644
--- a/src/pulsecore/sound-file-stream.c
+++ b/src/pulsecore/sound-file-stream.c
@@ -322,7 +322,7 @@ int pa_play_file(
data.sink = sink;
data.driver = __FILE__;
pa_sink_input_new_data_set_sample_spec(&data, &ss);
- pa_sink_input_new_data_set_volume(&data, volume);
+ pa_sink_input_new_data_set_virtual_volume(&data, volume);
pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, pa_path_get_filename(fname));
pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname);
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 1d21ffb..204e06c 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -685,15 +685,15 @@ int pa_source_output_start_move(pa_source_output *o) {
origin = o->source;
- pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0);
+ pa_idxset_remove_by_data(o->source->outputs, o, NULL);
if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED)
pa_assert_se(origin->n_corked-- >= 1);
- pa_idxset_remove_by_data(o->source->outputs, o, NULL);
- o->source = NULL;
+ pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0);
- pa_source_update_status(origin);
+ pa_source_update_status(o->source);
+ o->source = NULL;
return 0;
}
@@ -707,6 +707,9 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest) {
pa_assert(!o->source);
pa_source_assert_ref(dest);
+ if (!pa_source_output_may_move_to(o, dest))
+ return -1;
+
o->source = dest;
pa_idxset_put(o->source->outputs, o, NULL);
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 3cddd09..cd6ebc3 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -187,10 +187,12 @@ pa_source* pa_source_new(
s->n_corked = 0;
s->monitor_of = NULL;
- s->volume = data->volume;
+ s->virtual_volume = data->volume;
+ pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
+ s->base_volume = PA_VOLUME_NORM;
+ s->n_volume_steps = PA_VOLUME_NORM+1;
s->muted = data->muted;
s->refresh_volume = s->refresh_muted = FALSE;
- s->base_volume = PA_VOLUME_NORM;
reset_callbacks(s);
s->userdata = NULL;
@@ -206,8 +208,8 @@ pa_source* pa_source_new(
0);
s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
- pa_cvolume_reset(&s->thread_info.soft_volume, s->sample_spec.channels);
- s->thread_info.soft_muted = FALSE;
+ s->thread_info.soft_volume = s->soft_volume;
+ s->thread_info.soft_muted = s->muted;
s->thread_info.state = s->state;
s->thread_info.max_rewind = 0;
s->thread_info.requested_latency_valid = FALSE;
@@ -293,10 +295,13 @@ void pa_source_put(pa_source *s) {
if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL)) {
s->flags |= PA_SOURCE_DECIBEL_VOLUME;
- s->thread_info.soft_volume = s->volume;
+ s->thread_info.soft_volume = s->soft_volume;
s->thread_info.soft_muted = s->muted;
}
+ if (s->flags & PA_SOURCE_DECIBEL_VOLUME)
+ s->n_volume_steps = PA_VOLUME_NORM+1;
+
pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
@@ -568,32 +573,38 @@ pa_usec_t pa_source_get_latency(pa_source *s) {
/* Called from main thread */
void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
- pa_bool_t changed;
+ pa_cvolume old_virtual_volume;
+ pa_bool_t virtual_volume_changed;
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
pa_assert(volume);
+ pa_assert(pa_cvolume_valid(volume));
+ pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
- changed = !pa_cvolume_equal(volume, &s->volume);
- s->volume = *volume;
+ old_virtual_volume = s->virtual_volume;
+ s->virtual_volume = *volume;
+ virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
- if (s->set_volume && s->set_volume(s) < 0)
- s->set_volume = NULL;
+ if (s->set_volume) {
+ pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
+ s->set_volume(s);
+ } else
+ s->soft_volume = s->virtual_volume;
- if (!s->set_volume)
- pa_source_set_soft_volume(s, volume);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
- if (changed)
+ if (virtual_volume_changed)
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
-/* Called from main thread */
+/* Called from main thread. Only to be called by source implementor */
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);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
else
s->thread_info.soft_volume = *volume;
}
@@ -604,38 +615,36 @@ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
pa_assert(PA_SOURCE_IS_LINKED(s->state));
if (s->refresh_volume || force_refresh) {
- pa_cvolume old_volume = s->volume;
+ pa_cvolume old_virtual_volume = s->virtual_volume;
- if (s->get_volume && s->get_volume(s) < 0)
- s->get_volume = NULL;
+ if (s->get_volume)
+ s->get_volume(s);
- if (!s->get_volume)
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, &s->volume, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
- if (!pa_cvolume_equal(&old_volume, &s->volume))
+ if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
- return &s->volume;
+ return &s->virtual_volume;
}
/* Called from main thread */
void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
- pa_bool_t changed;
+ pa_bool_t old_muted;
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
- changed = s->muted != mute;
+ old_muted = s->muted;
s->muted = mute;
- if (s->set_mute && s->set_mute(s) < 0)
- s->set_mute = NULL;
+ if (s->set_mute)
+ s->set_mute(s);
- if (!s->set_mute)
- pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), 0, NULL, NULL);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
- if (changed)
+ if (old_muted != s->muted)
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
@@ -648,11 +657,10 @@ pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
if (s->refresh_muted || force_refresh) {
pa_bool_t old_muted = s->muted;
- if (s->get_mute && s->get_mute(s) < 0)
- s->get_mute = NULL;
+ if (s->get_mute)
+ s->get_mute(s);
- if (!s->get_mute)
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, &s->muted, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
if (old_muted != s->muted)
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
@@ -661,6 +669,7 @@ pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
return s->muted;
}
+/* Called from main thread */
pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
pa_source_assert_ref(s);
@@ -814,19 +823,17 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_
}
case PA_SOURCE_MESSAGE_SET_VOLUME:
- s->thread_info.soft_volume = *((pa_cvolume*) userdata);
+ s->thread_info.soft_volume = s->soft_volume;
return 0;
- case PA_SOURCE_MESSAGE_SET_MUTE:
- s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
+ case PA_SOURCE_MESSAGE_GET_VOLUME:
return 0;
- case PA_SOURCE_MESSAGE_GET_VOLUME:
- *((pa_cvolume*) userdata) = s->thread_info.soft_volume;
+ case PA_SOURCE_MESSAGE_SET_MUTE:
+ s->thread_info.soft_muted = s->muted;
return 0;
case PA_SOURCE_MESSAGE_GET_MUTE:
- *((pa_bool_t*) userdata) = s->thread_info.soft_muted;
return 0;
case PA_SOURCE_MESSAGE_SET_STATE:
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index 479cade..de23977 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -73,10 +73,11 @@ struct pa_source {
unsigned n_corked;
pa_sink *monitor_of; /* may be NULL */
- pa_cvolume volume;
- pa_bool_t muted;
-
pa_volume_t base_volume; /* shall be constant */
+ unsigned n_volume_steps; /* shall be constant */
+
+ pa_cvolume virtual_volume, soft_volume;
+ pa_bool_t muted:1;
pa_bool_t refresh_volume:1;
pa_bool_t refresh_muted:1;
@@ -95,23 +96,23 @@ struct pa_source {
* context. If this is NULL a PA_SOURCE_MESSAGE_GET_VOLUME message
* will be sent to the IO thread instead. If refresh_volume is
* FALSE neither this function is called nor a message is sent. */
- int (*get_volume)(pa_source *s); /* dito */
+ void (*get_volume)(pa_source *s); /* dito */
/* Called when the volume shall be changed. Called from main loop
* context. If this is NULL a PA_SOURCE_MESSAGE_SET_VOLUME message
* will be sent to the IO thread instead. */
- int (*set_volume)(pa_source *s); /* dito */
+ void (*set_volume)(pa_source *s); /* dito */
/* Called when the mute setting is queried. Called from main loop
* context. If this is NULL a PA_SOURCE_MESSAGE_GET_MUTE message
* will be sent to the IO thread instead. If refresh_mute is
* FALSE neither this function is called nor a message is sent.*/
- int (*get_mute)(pa_source *s); /* dito */
+ void (*get_mute)(pa_source *s); /* dito */
/* Called when the mute setting shall be changed. Called from main
* loop context. If this is NULL a PA_SOURCE_MESSAGE_SET_MUTE
* message will be sent to the IO thread instead. */
- int (*set_mute)(pa_source *s); /* dito */
+ void (*set_mute)(pa_source *s); /* dito */
/* Called when a the requested latency is changed. Called from IO
* thread context. */
@@ -122,6 +123,7 @@ struct pa_source {
struct {
pa_source_state_t state;
pa_hashmap *outputs;
+
pa_cvolume soft_volume;
pa_bool_t soft_muted:1;
@@ -189,7 +191,7 @@ void pa_source_new_data_set_volume(pa_source_new_data *data, const pa_cvolume *v
void pa_source_new_data_set_muted(pa_source_new_data *data, pa_bool_t mute);
void pa_source_new_data_done(pa_source_new_data *data);
-/* To be called exclusively by the source driver, from main context */
+/*** To be called exclusively by the source driver, from main context */
pa_source* pa_source_new(
pa_core *core,
@@ -208,7 +210,9 @@ void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t
void pa_source_detach(pa_source *s);
void pa_source_attach(pa_source *s);
-/* May be called by everyone, from main context */
+void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume);
+
+/*** May be called by everyone, from main context */
/* The returned value is supposed to be in the time domain of the sound card! */
pa_usec_t pa_source_get_latency(pa_source *s);
@@ -222,7 +226,6 @@ 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);
-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 force_refresh);
@@ -239,7 +242,7 @@ pa_queue *pa_source_move_all_start(pa_source *s);
void pa_source_move_all_finish(pa_source *s, pa_queue *q);
void pa_source_move_all_fail(pa_queue *q);
-/* To be called exclusively by the source driver, from IO context */
+/*** To be called exclusively by the source driver, from IO context */
void pa_source_post(pa_source*s, const pa_memchunk *chunk);
void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk);
@@ -255,7 +258,7 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s);
void pa_source_set_max_rewind(pa_source *s, size_t max_rewind);
void pa_source_update_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency);
-/* To be called exclusively by source output drivers, from IO context */
+/*** To be called exclusively by source output drivers, from IO context */
void pa_source_invalidate_requested_latency(pa_source *s);
--
hooks/post-receive
PulseAudio Sound Server
More information about the pulseaudio-commits
mailing list