summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore2
-rw-r--r--src/Makefile.am94
-rw-r--r--src/daemon/cmdline.c5
-rw-r--r--src/daemon/cpulimit.c2
-rw-r--r--src/daemon/daemon-conf.c27
-rwxr-xr-xsrc/daemon/default.pa.in2
-rwxr-xr-xsrc/daemon/esdcompat.in2
-rw-r--r--src/daemon/main.c1
-rwxr-xr-xsrc/daemon/system.pa.in6
-rw-r--r--src/modules/.gitignore1
-rw-r--r--src/modules/alsa/alsa-mixer.c655
-rw-r--r--src/modules/alsa/alsa-mixer.h36
-rw-r--r--src/modules/alsa/alsa-source.c2
-rw-r--r--src/modules/alsa/alsa-util.c2
-rw-r--r--src/modules/alsa/mixer/paths/analog-input-dock-mic.conf81
-rw-r--r--src/modules/alsa/mixer/paths/analog-input-front-mic.conf81
-rw-r--r--src/modules/alsa/mixer/paths/analog-input-internal-mic.conf84
-rw-r--r--src/modules/alsa/mixer/paths/analog-input-linein.conf32
-rw-r--r--src/modules/alsa/mixer/paths/analog-input-mic.conf75
-rw-r--r--src/modules/alsa/mixer/paths/analog-input-mic.conf.common79
-rw-r--r--src/modules/alsa/mixer/paths/analog-input-rear-mic.conf81
-rw-r--r--src/modules/alsa/mixer/paths/analog-input.conf28
-rw-r--r--src/modules/alsa/mixer/paths/analog-input.conf.common45
-rw-r--r--src/modules/alsa/mixer/paths/analog-output.conf.common6
-rw-r--r--src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules2
-rw-r--r--src/modules/alsa/mixer/profile-sets/default.conf65
-rw-r--r--src/modules/alsa/mixer/profile-sets/native-instruments-traktor-audio10.conf131
-rw-r--r--src/modules/alsa/mixer/profile-sets/native-instruments-traktor-audio6.conf92
-rw-r--r--src/modules/alsa/module-alsa-card.c18
-rw-r--r--src/modules/alsa/module-alsa-sink.c4
-rw-r--r--src/modules/alsa/module-alsa-source.c2
-rw-r--r--src/modules/bluetooth/bluetooth-util.c94
-rw-r--r--src/modules/bluetooth/bluetooth-util.h4
-rw-r--r--src/modules/bluetooth/module-bluetooth-device.c246
-rw-r--r--src/modules/bluetooth/module-bluetooth-proximity.c1
-rw-r--r--src/modules/bluetooth/sbc/sbc.c (renamed from src/modules/bluetooth/sbc.c)168
-rw-r--r--src/modules/bluetooth/sbc/sbc.h (renamed from src/modules/bluetooth/sbc.h)2
-rw-r--r--src/modules/bluetooth/sbc/sbc_math.h (renamed from src/modules/bluetooth/sbc_math.h)0
-rw-r--r--src/modules/bluetooth/sbc/sbc_primitives.c (renamed from src/modules/bluetooth/sbc_primitives.c)89
-rw-r--r--src/modules/bluetooth/sbc/sbc_primitives.h (renamed from src/modules/bluetooth/sbc_primitives.h)4
-rw-r--r--src/modules/bluetooth/sbc/sbc_primitives_armv6.c299
-rw-r--r--src/modules/bluetooth/sbc/sbc_primitives_armv6.h52
-rw-r--r--src/modules/bluetooth/sbc/sbc_primitives_iwmmxt.c304
-rw-r--r--src/modules/bluetooth/sbc/sbc_primitives_iwmmxt.h42
-rw-r--r--src/modules/bluetooth/sbc/sbc_primitives_mmx.c (renamed from src/modules/bluetooth/sbc_primitives_mmx.c)58
-rw-r--r--src/modules/bluetooth/sbc/sbc_primitives_mmx.h (renamed from src/modules/bluetooth/sbc_primitives_mmx.h)0
-rw-r--r--src/modules/bluetooth/sbc/sbc_primitives_neon.c892
-rw-r--r--src/modules/bluetooth/sbc/sbc_primitives_neon.h (renamed from src/modules/bluetooth/sbc_primitives_neon.h)0
-rw-r--r--src/modules/bluetooth/sbc/sbc_tables.h (renamed from src/modules/bluetooth/sbc_tables.h)0
-rw-r--r--src/modules/bluetooth/sbc_primitives_neon.c246
-rw-r--r--src/modules/coreaudio/module-coreaudio-detect.c4
-rw-r--r--src/modules/coreaudio/module-coreaudio-device.c2
-rw-r--r--src/modules/dbus/iface-device.c9
-rw-r--r--src/modules/dbus/iface-stream.c135
-rw-r--r--src/modules/echo-cancel/adrian.c12
-rw-r--r--src/modules/echo-cancel/module-echo-cancel.c31
-rw-r--r--src/modules/echo-cancel/speex.c14
-rw-r--r--src/modules/jack/module-jack-sink.c2
-rw-r--r--src/modules/jack/module-jackdbus-detect.c30
-rw-r--r--src/modules/module-augment-properties.c7
-rw-r--r--src/modules/module-card-restore.c2
-rw-r--r--src/modules/module-combine.c2
-rw-r--r--src/modules/module-console-kit.c2
-rw-r--r--src/modules/module-cork-music-on-phone.c27
-rw-r--r--src/modules/module-detect.c2
-rw-r--r--src/modules/module-device-manager.c10
-rw-r--r--src/modules/module-device-restore.c2
-rw-r--r--src/modules/module-equalizer-sink.c8
-rw-r--r--src/modules/module-hal-detect.c4
-rw-r--r--src/modules/module-intended-roles.c2
-rw-r--r--src/modules/module-ladspa-sink.c387
-rw-r--r--src/modules/module-loopback.c4
-rw-r--r--src/modules/module-match.c2
-rw-r--r--src/modules/module-pipe-sink.c4
-rw-r--r--src/modules/module-position-event-sounds.c2
-rw-r--r--src/modules/module-protocol-stub.c4
-rw-r--r--src/modules/module-remap-sink.c3
-rw-r--r--src/modules/module-rygel-media-server.c15
-rw-r--r--src/modules/module-solaris.c6
-rw-r--r--src/modules/module-stream-restore.c16
-rw-r--r--src/modules/module-suspend-on-idle.c1
-rw-r--r--src/modules/module-tunnel.c9
-rw-r--r--src/modules/module-udev-detect.c3
-rw-r--r--src/modules/module-virtual-sink.c53
-rw-r--r--src/modules/module-virtual-source.c14
-rw-r--r--src/modules/module-volume-restore.c2
-rw-r--r--src/modules/module-waveout.c6
-rw-r--r--src/modules/oss/module-oss.c2
-rw-r--r--src/modules/raop/base64.c12
-rw-r--r--src/modules/raop/raop_client.c33
-rw-r--r--src/modules/rtp/rtp.h3
-rw-r--r--src/modules/rtp/rtsp_client.c6
-rw-r--r--src/modules/udev-util.c2
-rw-r--r--src/pulse/browser.c2
-rw-r--r--src/pulse/context.c13
-rw-r--r--src/pulse/def.h11
-rw-r--r--src/pulse/ext-device-manager.c5
-rw-r--r--src/pulse/ext-stream-restore.c5
-rw-r--r--src/pulse/glib-mainloop.c4
-rw-r--r--src/pulse/introspect.c11
-rw-r--r--src/pulse/introspect.h2
-rw-r--r--src/pulse/mainloop-api.h2
-rw-r--r--src/pulse/scache.c4
-rw-r--r--src/pulse/stream.c8
-rw-r--r--src/pulse/subscribe.c1
-rw-r--r--src/pulse/volume.c15
-rw-r--r--src/pulse/volume.h7
-rw-r--r--src/pulsecore/asyncq.c5
-rw-r--r--src/pulsecore/card.c2
-rw-r--r--src/pulsecore/cli-command.c8
-rw-r--r--src/pulsecore/cli-text.c20
-rw-r--r--src/pulsecore/core-scache.c1
-rw-r--r--src/pulsecore/core-util.c27
-rw-r--r--src/pulsecore/core.h3
-rw-r--r--src/pulsecore/cpu-arm.c38
-rw-r--r--src/pulsecore/cpu-orc.c34
-rw-r--r--src/pulsecore/cpu-orc.h37
-rw-r--r--src/pulsecore/cpu-x86.c26
-rw-r--r--src/pulsecore/database-simple.c2
-rw-r--r--src/pulsecore/envelope.c989
-rw-r--r--src/pulsecore/envelope.h56
-rw-r--r--src/pulsecore/ipacl.c4
-rw-r--r--src/pulsecore/log.c27
-rw-r--r--src/pulsecore/log.h5
-rw-r--r--src/pulsecore/ltdl-helper.c4
-rw-r--r--src/pulsecore/memblock.c10
-rw-r--r--src/pulsecore/memblockq.c4
-rw-r--r--src/pulsecore/memtrap.c2
-rw-r--r--src/pulsecore/modargs.c2
-rw-r--r--src/pulsecore/module.c2
-rw-r--r--src/pulsecore/play-memblockq.c6
-rw-r--r--src/pulsecore/poll.c4
-rw-r--r--src/pulsecore/poll.h7
-rw-r--r--src/pulsecore/protocol-esound.c3
-rw-r--r--src/pulsecore/protocol-native.c62
-rw-r--r--src/pulsecore/remap.c18
-rw-r--r--src/pulsecore/remap_mmx.c8
-rw-r--r--src/pulsecore/remap_sse.c6
-rw-r--r--src/pulsecore/resampler.c14
-rw-r--r--src/pulsecore/rtpoll.c2
-rw-r--r--src/pulsecore/sample-util.c4
-rw-r--r--src/pulsecore/sconv-s16le.c3
-rw-r--r--src/pulsecore/sconv.c6
-rw-r--r--src/pulsecore/sconv_sse.c33
-rw-r--r--src/pulsecore/semaphore-osx.c3
-rw-r--r--src/pulsecore/semaphore-win32.c3
-rw-r--r--src/pulsecore/shm.c2
-rw-r--r--src/pulsecore/sink-input.c622
-rw-r--r--src/pulsecore/sink-input.h28
-rw-r--r--src/pulsecore/sink.c602
-rw-r--r--src/pulsecore/sink.h6
-rw-r--r--src/pulsecore/sndfile-util.c16
-rw-r--r--src/pulsecore/sound-file-stream.c2
-rw-r--r--src/pulsecore/source-output.c1
-rw-r--r--src/pulsecore/source-output.h4
-rw-r--r--src/pulsecore/source.c35
-rw-r--r--src/pulsecore/source.h3
-rw-r--r--src/pulsecore/strbuf.c2
-rw-r--r--src/pulsecore/strlist.c2
-rw-r--r--src/pulsecore/svolume.orc84
-rw-r--r--src/pulsecore/svolume_arm.c41
-rw-r--r--src/pulsecore/svolume_c.c73
-rw-r--r--src/pulsecore/svolume_mmx.c52
-rw-r--r--src/pulsecore/svolume_orc.c117
-rw-r--r--src/pulsecore/svolume_sse.c46
-rw-r--r--src/pulsecore/time-smoother.c4
-rw-r--r--src/pulsecore/usergroup.c16
-rw-r--r--src/pulsecore/x11prop.c3
-rw-r--r--src/tests/cpulimit-test.c4
-rw-r--r--src/tests/envelope-test.c243
-rw-r--r--src/tests/mainloop-test.c2
-rw-r--r--src/tests/memblockq-test.c2
-rw-r--r--src/tests/mix-test.c10
-rw-r--r--src/tests/rtstutter.c2
-rw-r--r--src/tests/usergroup-test.c18
-rw-r--r--src/utils/pacat.c6
-rw-r--r--src/utils/pacmd.c3
-rw-r--r--src/utils/pactl.c2
-rw-r--r--src/utils/padsp.c6
-rw-r--r--src/utils/pax11publish.c3
180 files changed, 5425 insertions, 3357 deletions
diff --git a/src/.gitignore b/src/.gitignore
index c93974bf..e56c225d 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -24,7 +24,6 @@ cpulimit-test2
daemon.conf
default.pa
system.pa
-envelope-test
esdcompat
flist-test
gconf-helper
@@ -66,3 +65,4 @@ voltest
start-pulseaudio-x11
start-pulseaudio-kde
vector-test
+*-symdef.h
diff --git a/src/Makefile.am b/src/Makefile.am
index f160c944..fca7edad 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -261,7 +261,6 @@ TESTS = \
smoother-test \
mix-test \
remix-test \
- envelope-test \
proplist-test \
lock-autospawn-test \
prioq-test
@@ -296,7 +295,6 @@ TESTS_BINARIES = \
smoother-test \
mix-test \
remix-test \
- envelope-test \
proplist-test \
rtstutter \
stripnul \
@@ -516,11 +514,6 @@ smoother_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINOR@.la libpulse.la li
smoother_test_CFLAGS = $(AM_CFLAGS)
smoother_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
-envelope_test_SOURCES = tests/envelope-test.c
-envelope_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINOR@.la libpulse.la libpulsecommon-@PA_MAJORMINOR@.la
-envelope_test_CFLAGS = $(AM_CFLAGS)
-envelope_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
-
proplist_test_SOURCES = tests/proplist-test.c
proplist_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINOR@.la libpulse.la libpulsecommon-@PA_MAJORMINOR@.la
proplist_test_CFLAGS = $(AM_CFLAGS)
@@ -838,7 +831,6 @@ libpulsecore_@PA_MAJORMINOR@_la_SOURCES = \
pulsecore/core-scache.c pulsecore/core-scache.h \
pulsecore/core-subscribe.c pulsecore/core-subscribe.h \
pulsecore/core.c pulsecore/core.h \
- pulsecore/envelope.c pulsecore/envelope.h \
pulsecore/fdsem.c pulsecore/fdsem.h \
pulsecore/g711.c pulsecore/g711.h \
pulsecore/hook-list.c pulsecore/hook-list.h \
@@ -859,6 +851,7 @@ libpulsecore_@PA_MAJORMINOR@_la_SOURCES = \
pulsecore/cpu.h \
pulsecore/cpu-arm.c pulsecore/cpu-arm.h \
pulsecore/cpu-x86.c pulsecore/cpu-x86.h \
+ pulsecore/cpu-orc.c pulsecore/cpu-orc.h \
pulsecore/svolume_c.c pulsecore/svolume_arm.c \
pulsecore/svolume_mmx.c pulsecore/svolume_sse.c \
pulsecore/sconv-s16be.c pulsecore/sconv-s16be.h \
@@ -883,6 +876,14 @@ libpulsecore_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(
libpulsecore_@PA_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
libpulsecore_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSPEEX_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LTLIBICONV) libpulsecommon-@PA_MAJORMINOR@.la libpulse.la libpulsecore-foreign.la
+if HAVE_ORC
+ORC_SOURCE += pulsecore/svolume
+libpulsecore_@PA_MAJORMINOR@_la_SOURCES += pulsecore/svolume_orc.c
+nodist_libpulsecore_@PA_MAJORMINOR@_la_SOURCES = pulsecore/svolume-orc-gen.c pulsecore/svolume-orc-gen.h
+libpulsecore_@PA_MAJORMINOR@_la_CFLAGS += $(ORC_CFLAGS)
+libpulsecore_@PA_MAJORMINOR@_la_LIBADD += $(ORC_LIBS)
+endif
+
if HAVE_X11
libpulsecore_@PA_MAJORMINOR@_la_SOURCES += pulsecore/x11wrap.c pulsecore/x11wrap.h
libpulsecore_@PA_MAJORMINOR@_la_CFLAGS += $(X11_CFLAGS)
@@ -1108,6 +1109,8 @@ dist_alsaprofilesets_DATA = \
modules/alsa/mixer/profile-sets/maudio-fasttrack-pro.conf \
modules/alsa/mixer/profile-sets/native-instruments-audio4dj.conf \
modules/alsa/mixer/profile-sets/native-instruments-audio8dj.conf \
+ modules/alsa/mixer/profile-sets/native-instruments-traktor-audio6.conf \
+ modules/alsa/mixer/profile-sets/native-instruments-traktor-audio10.conf \
modules/alsa/mixer/profile-sets/native-instruments-traktorkontrol-s4.conf \
modules/alsa/mixer/profile-sets/native-instruments-korecontroller.conf
@@ -1121,9 +1124,12 @@ dist_alsapaths_DATA = \
modules/alsa/mixer/paths/analog-input.conf \
modules/alsa/mixer/paths/analog-input.conf.common \
modules/alsa/mixer/paths/analog-input-fm.conf \
- modules/alsa/mixer/paths/analog-input-internal-mic.conf \
modules/alsa/mixer/paths/analog-input-linein.conf \
modules/alsa/mixer/paths/analog-input-mic.conf \
+ modules/alsa/mixer/paths/analog-input-dock-mic.conf \
+ modules/alsa/mixer/paths/analog-input-front-mic.conf \
+ modules/alsa/mixer/paths/analog-input-internal-mic.conf \
+ modules/alsa/mixer/paths/analog-input-rear-mic.conf \
modules/alsa/mixer/paths/analog-input-mic.conf.common \
modules/alsa/mixer/paths/analog-input-mic-line.conf \
modules/alsa/mixer/paths/analog-input-tvtuner.conf \
@@ -1332,7 +1338,7 @@ $(SYMDEF_FILES): modules/module-defs.h.m4
.PHONY: builddirs
builddirs:
- $(AM_V_at)$(MKDIR_P) daemon modules src/modules/echo-cancel
+ $(AM_V_at)$(MKDIR_P) daemon modules
# Simple protocol
@@ -1538,19 +1544,24 @@ module_oss_la_LIBADD = $(MODULE_LIBADD) liboss-util.la
module_coreaudio_detect_la_SOURCES = modules/coreaudio/module-coreaudio-detect.c
module_coreaudio_detect_la_LDFLAGS = $(MODULE_LDFLAGS) \
- -Wl,-framework -Wl,Cocoa -framework CoreAudio \
- -Wl,-framework -Wl,AudioUnit -framework AudioUnit
+ -Wl,-framework -Wl,Cocoa -framework CoreAudio \
+ -Wl,-framework -Wl,AudioUnit -framework AudioUnit
module_coreaudio_detect_la_LIBADD = $(MODULE_LIBADD)
module_coreaudio_device_la_SOURCES = modules/coreaudio/module-coreaudio-device.c
module_coreaudio_device_la_LDFLAGS = $(MODULE_LDFLAGS) \
- -Wl,-framework -Wl,Cocoa -framework CoreAudio \
- -Wl,-framework -Wl,AudioUnit -framework AudioUnit
+ -Wl,-framework -Wl,Cocoa -framework CoreAudio \
+ -Wl,-framework -Wl,AudioUnit -framework AudioUnit
module_coreaudio_device_la_LIBADD = $(MODULE_LIBADD)
# ALSA
-libalsa_util_la_SOURCES = modules/alsa/alsa-util.c modules/alsa/alsa-util.h modules/alsa/alsa-mixer.c modules/alsa/alsa-mixer.h modules/alsa/alsa-sink.c modules/alsa/alsa-sink.h modules/alsa/alsa-source.c modules/alsa/alsa-source.h modules/reserve-wrap.c modules/reserve-wrap.h
+libalsa_util_la_SOURCES = \
+ modules/alsa/alsa-util.c modules/alsa/alsa-util.h \
+ modules/alsa/alsa-mixer.c modules/alsa/alsa-mixer.h \
+ modules/alsa/alsa-sink.c modules/alsa/alsa-sink.h \
+ modules/alsa/alsa-source.c modules/alsa/alsa-source.h \
+ modules/reserve-wrap.c modules/reserve-wrap.h
libalsa_util_la_LDFLAGS = -avoid-version
libalsa_util_la_LIBADD = $(MODULE_LIBADD) $(ASOUNDLIB_LIBS)
libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
@@ -1724,18 +1735,19 @@ module_suspend_on_idle_la_LIBADD = $(MODULE_LIBADD)
module_suspend_on_idle_la_CFLAGS = $(AM_CFLAGS)
# echo-cancel module
-module_echo_cancel_la_SOURCES = modules/echo-cancel/module-echo-cancel.c modules/echo-cancel/echo-cancel.h \
- modules/echo-cancel/speex.c \
- modules/echo-cancel/adrian-aec.c modules/echo-cancel/adrian-aec.h \
- modules/echo-cancel/adrian.c modules/echo-cancel/adrian.h
+module_echo_cancel_la_SOURCES = \
+ modules/echo-cancel/module-echo-cancel.c modules/echo-cancel/echo-cancel.h \
+ modules/echo-cancel/speex.c \
+ modules/echo-cancel/adrian-aec.c modules/echo-cancel/adrian-aec.h \
+ modules/echo-cancel/adrian.c modules/echo-cancel/adrian.h
module_echo_cancel_la_LDFLAGS = $(MODULE_LDFLAGS)
module_echo_cancel_la_LIBADD = $(MODULE_LIBADD) $(LIBSPEEX_LIBS)
module_echo_cancel_la_CFLAGS = $(AM_CFLAGS) $(LIBSPEEX_CFLAGS)
if HAVE_ORC
ORC_SOURCE += modules/echo-cancel/adrian-aec
nodist_module_echo_cancel_la_SOURCES = \
- modules/echo-cancel/adrian-aec-orc-gen.c \
- modules/echo-cancel/adrian-aec-orc-gen.h
+ modules/echo-cancel/adrian-aec-orc-gen.c \
+ modules/echo-cancel/adrian-aec-orc-gen.h
module_echo_cancel_la_LIBADD += $(ORC_LIBS)
module_echo_cancel_la_CFLAGS += $(ORC_CFLAGS) -I$(top_builddir)/src/modules/echo-cancel
endif
@@ -1817,15 +1829,23 @@ module_bluetooth_discover_la_LDFLAGS = $(MODULE_LDFLAGS)
module_bluetooth_discover_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) libbluetooth-util.la
module_bluetooth_discover_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
-libbluetooth_sbc_la_SOURCES = modules/bluetooth/sbc.c modules/bluetooth/sbc.h modules/bluetooth/sbc_tables.h modules/bluetooth/sbc_math.h modules/bluetooth/sbc_primitives.h modules/bluetooth/sbc_primitives.c modules/bluetooth/sbc_primitives_mmx.h modules/bluetooth/sbc_primitives_neon.h modules/bluetooth/sbc_primitives_mmx.c modules/bluetooth/sbc_primitives_neon.c
+libbluetooth_sbc_la_SOURCES = \
+ modules/bluetooth/sbc/sbc.c modules/bluetooth/sbc/sbc.h \
+ modules/bluetooth/sbc/sbc_primitives.c modules/bluetooth/sbc/sbc_primitives.h \
+ modules/bluetooth/sbc/sbc_primitives_armv6.h modules/bluetooth/sbc/sbc_primitives_armv6.c \
+ modules/bluetooth/sbc/sbc_primitives_iwmmxt.h modules/bluetooth/sbc/sbc_primitives_iwmmxt.c \
+ modules/bluetooth/sbc/sbc_primitives_mmx.c modules/bluetooth/sbc/sbc_primitives_mmx.h \
+ modules/bluetooth/sbc/sbc_primitives_neon.c modules/bluetooth/sbc/sbc_primitives_neon.h \
+ modules/bluetooth/sbc/sbc_math.h \
+ modules/bluetooth/sbc/sbc_tables.h
libbluetooth_sbc_la_LDFLAGS = -avoid-version
libbluetooth_sbc_la_LIBADD = $(MODULE_LIBADD)
-libbluetooth_sbc_la_CFLAGS = $(AM_CFLAGS)
+libbluetooth_sbc_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/src/modules/bluetooth/sbc
BLUETOOTH_SBC_FILES = $(subst modules/bluetooth/,,$(libbluetooth_sbc_la_SOURCES))
libbluetooth_ipc_la_SOURCES = modules/bluetooth/ipc.c modules/bluetooth/ipc.h
libbluetooth_ipc_la_LDFLAGS = -avoid-version
-libbluetooth_ipc_la_LIBADD = $(AM_LIBADD)libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la
+libbluetooth_ipc_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la
libbluetooth_ipc_la_CFLAGS = $(AM_CFLAGS)
BLUETOOTH_IPC_FILES = $(subst modules/bluetooth/,,$(libbluetooth_ipc_la_SOURCES)) rtp.h
@@ -1837,7 +1857,7 @@ libbluetooth_util_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
module_bluetooth_device_la_SOURCES = modules/bluetooth/module-bluetooth-device.c modules/bluetooth/rtp.h
module_bluetooth_device_la_LDFLAGS = $(MODULE_LDFLAGS)
module_bluetooth_device_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) libbluetooth-util.la libbluetooth-ipc.la libbluetooth-sbc.la
-module_bluetooth_device_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
+module_bluetooth_device_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) -I$(top_srcdir)/src/modules/bluetooth/sbc
# Apple Airtunes/RAOP
module_raop_sink_la_SOURCES = modules/raop/module-raop-sink.c
@@ -1863,23 +1883,23 @@ module_rygel_media_server_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
CLEANFILES += esdcompat client.conf default.pa system.pa daemon.conf start-pulseaudio-x11 start-pulseaudio-kde daemon/pulseaudio.desktop daemon/pulseaudio-kde.desktop
esdcompat: daemon/esdcompat.in Makefile
- sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \
+ $(AM_V_GEN) sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \
-e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \
-e 's,@PA_BINARY\@,$(PA_BINARY),g' < $< > $@
- chmod +x esdcompat
+ $(AM_V_at) chmod +x esdcompat
start-pulseaudio-x11: daemon/start-pulseaudio-x11.in Makefile
- sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' \
+ $(AM_V_GEN) sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' \
-e 's,@PACTL_BINARY\@,$(bindir)/pactl,g' < $< > $@
- chmod +x start-pulseaudio-x11
+ $(AM_V_at) chmod +x start-pulseaudio-x11
start-pulseaudio-kde: daemon/start-pulseaudio-kde.in Makefile
- sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' \
+ $(AM_V_GEN) sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' \
-e 's,@PACTL_BINARY\@,$(bindir)/pactl,g' < $< > $@
- chmod +x start-pulseaudio-kde
+ $(AM_V_at) chmod +x start-pulseaudio-kde
client.conf: pulse/client.conf.in Makefile
- sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' < $< > $@
+ $(AM_V_GEN) sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' < $< > $@
if OS_IS_WIN32
default.pa: daemon/default.pa.win32
@@ -1888,17 +1908,17 @@ system.pa: daemon/default.pa.win32
cp $< $@
else
default.pa: daemon/default.pa.in Makefile
- sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' \
+ $(AM_V_GEN) sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' \
-e 's,@PA_DLSEARCHPATH\@,$(modlibexecdir),g' \
-e 's,@PA_SOEXT\@,.so,g' < $< > $@
system.pa: daemon/system.pa.in Makefile
- sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' \
+ $(AM_V_GEN) sed -e 's,@PA_BINARY\@,$(PA_BINARY),g' \
-e 's,@PA_DLSEARCHPATH\@,$(modlibexecdir),g' \
-e 's,@PA_SOEXT\@,.so,g' < $< > $@
endif
daemon.conf: daemon/daemon.conf.in Makefile
- sed -e 's,@PA_DLSEARCHPATH\@,$(modlibexecdir),g' \
+ $(AM_V_GEN) sed -e 's,@PA_DLSEARCHPATH\@,$(modlibexecdir),g' \
-e 's,@PA_DEFAULT_CONFIG_FILE\@,$(DEFAULT_CONFIG_DIR),g' < $< > $@
if OS_IS_WIN32
@@ -1935,8 +1955,8 @@ update-ffmpeg:
# We get things twice here, because sometimes gitweb will us just give a "Generating..." otherwise.
update-sbc:
for i in $(BLUETOOTH_SBC_FILES) ; do \
- wget -O /dev/null http://git.kernel.org/\?p=bluetooth/bluez.git\;a=blob_plain\;f=sbc/$$i ; \
- wget -O modules/bluetooth/$$i http://git.kernel.org/\?p=bluetooth/bluez.git\;a=blob_plain\;f=sbc/$$i ; \
+ wget -O /dev/null http://git.kernel.org/\?p=bluetooth/bluez.git\;a=blob_plain\;f=$$i ; \
+ wget -O modules/bluetooth/$$i http://git.kernel.org/\?p=bluetooth/bluez.git\;a=blob_plain\;f=$$i ; \
done
for i in $(BLUETOOTH_IPC_FILES); do \
wget -O /dev/null http://git.kernel.org/\?p=bluetooth/bluez.git\;a=blob_plain\;f=audio/$$i ; \
diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c
index f6cdcdc8..4854affc 100644
--- a/src/daemon/cmdline.c
+++ b/src/daemon/cmdline.c
@@ -145,7 +145,8 @@ void pa_cmdline_help(const char *argv0) {
" this time passed\n"
" --log-level[=LEVEL] Increase or set verbosity level\n"
" -v Increase the verbosity level\n"
- " --log-target={auto,syslog,stderr} Specify the log target\n"
+ " --log-target={auto,syslog,stderr,file:PATH}\n"
+ " Specify the log target\n"
" --log-meta[=BOOL] Include code location in log messages\n"
" --log-time[=BOOL] Include timestamps in log messages\n"
" --log-backtrace=FRAMES Include a backtrace in log messages\n"
@@ -318,7 +319,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d
case ARG_LOG_TARGET:
if (pa_daemon_conf_set_log_target(conf, optarg) < 0) {
- pa_log(_("Invalid log target: use either 'syslog', 'stderr' or 'auto'."));
+ pa_log(_("Invalid log target: use either 'syslog', 'stderr' or 'auto' or a valid file name 'file:<path>'."));
goto fail;
}
break;
diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c
index c1c2a6f6..9e22d7e8 100644
--- a/src/daemon/cpulimit.c
+++ b/src/daemon/cpulimit.c
@@ -86,7 +86,7 @@ static struct sigaction sigaction_prev;
static pa_bool_t installed = FALSE;
/* The current state of operation */
-static enum {
+static enum {
PHASE_IDLE, /* Normal state */
PHASE_SOFT /* After CPU overload has been detected */
} phase = PHASE_IDLE;
diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index f640b039..9b530a80 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <fcntl.h>
#ifdef HAVE_SCHED_H
#include <sched.h>
@@ -180,6 +181,9 @@ pa_daemon_conf* pa_daemon_conf_new(void) {
void pa_daemon_conf_free(pa_daemon_conf *c) {
pa_assert(c);
+
+ pa_log_set_fd(-1);
+
pa_xfree(c->script_commands);
pa_xfree(c->dl_search_path);
pa_xfree(c->default_script_file);
@@ -225,6 +229,23 @@ int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) {
c->log_level = PA_LOG_WARN;
else if (pa_startswith(string, "err"))
c->log_level = PA_LOG_ERROR;
+ else if (pa_startswith(string, "file:")) {
+ char file_path[512];
+ int log_fd;
+
+ pa_strlcpy(file_path, string + 5, sizeof(file_path));
+
+ /* Open target file with user rights */
+ if ((log_fd = open(file_path, O_RDWR|O_TRUNC|O_CREAT, S_IRWXU)) >= 0) {
+ c->auto_log_target = 0;
+ c->log_target = PA_LOG_FD;
+ pa_log_set_fd(log_fd);
+ }
+ else {
+ printf("Failed to open target file %s, error : %s\n", file_path, pa_cstrerror(errno));
+ return -1;
+ }
+ }
else
return -1;
@@ -307,8 +328,8 @@ static int parse_resample_method(const char *filename, unsigned line, const char
return 0;
}
-static int parse_rlimit(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
#ifdef HAVE_SYS_RESOURCE_H
+static int parse_rlimit(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
struct pa_rlimit *r = data;
pa_assert(filename);
@@ -329,12 +350,10 @@ static int parse_rlimit(const char *filename, unsigned line, const char *section
r->is_set = k >= 0;
r->value = k >= 0 ? (rlim_t) k : 0;
}
-#else
- pa_log_warn(_("[%s:%u] rlimit not supported on this platform."), filename, line);
-#endif
return 0;
}
+#endif
static int parse_sample_format(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
pa_daemon_conf *c = data;
diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
index ace0f09e..32ba5826 100755
--- a/src/daemon/default.pa.in
+++ b/src/daemon/default.pa.in
@@ -39,7 +39,7 @@ load-module module-card-restore
load-module module-augment-properties
### Load audio drivers statically (it's probably better to not load
-### these drivers manually, but instead use module-hal-detect --
+### these drivers manually, but instead use module-udev-detect --
### see below -- for doing this automatically)
#load-module module-alsa-sink
#load-module module-alsa-source device=hw:1,0
diff --git a/src/daemon/esdcompat.in b/src/daemon/esdcompat.in
index 66501803..41a12a02 100755
--- a/src/daemon/esdcompat.in
+++ b/src/daemon/esdcompat.in
@@ -59,7 +59,7 @@ Ignored directives:
-terminate terminate esd daemone after last client exits
-nobeeps disable startup beeps
-trust start esd even if use of /tmp/.esd can be insecure
- -port PORT listen for connections at PORT (only for tcp/ip)
+ -port PORT listen for connections at PORT (only for tcp/ip)
-bind ADDRESS binds to ADDRESS (only for tcp/ip)
EOF
exit 0
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 243e7c0a..533c4c32 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -966,6 +966,7 @@ int main(int argc, char *argv[]) {
c->cpu_info.cpu_type = PA_CPU_X86;
if (pa_cpu_init_arm(&(c->cpu_info.flags.arm)))
c->cpu_info.cpu_type = PA_CPU_ARM;
+ pa_cpu_init_orc(c->cpu_info);
}
pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0);
diff --git a/src/daemon/system.pa.in b/src/daemon/system.pa.in
index 0ca32bd3..aaefd1d1 100755
--- a/src/daemon/system.pa.in
+++ b/src/daemon/system.pa.in
@@ -20,11 +20,11 @@
# mode.
### Automatically load driver modules depending on the hardware available
-.ifexists module-hal-detect@PA_SOEXT@
-load-module module-hal-detect
+.ifexists module-udev-detect@PA_SOEXT@
+load-module module-udev-detect
.else
### Alternatively use the static hardware detection module (for systems that
-### lack HAL support)
+### lack udev support)
load-module module-detect
.endif
diff --git a/src/modules/.gitignore b/src/modules/.gitignore
deleted file mode 100644
index 2d2d942d..00000000
--- a/src/modules/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-module-*-symdef.h
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 946cbe24..3eef5f9c 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -491,6 +491,15 @@ static void option_free(pa_alsa_option *o) {
pa_xfree(o);
}
+static void decibel_fix_free(pa_alsa_decibel_fix *db_fix) {
+ pa_assert(db_fix);
+
+ pa_xfree(db_fix->name);
+ pa_xfree(db_fix->db_values);
+
+ pa_xfree(db_fix);
+}
+
static void element_free(pa_alsa_element *e) {
pa_alsa_option *o;
pa_assert(e);
@@ -500,6 +509,9 @@ static void element_free(pa_alsa_element *e) {
option_free(o);
}
+ if (e->db_fix)
+ decibel_fix_free(e->db_fix);
+
pa_xfree(e->alsa_name);
pa_xfree(e);
}
@@ -593,14 +605,60 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
long value = 0;
if (e->direction == PA_ALSA_DIRECTION_OUTPUT) {
- if (snd_mixer_selem_has_playback_channel(me, c))
- r = snd_mixer_selem_get_playback_dB(me, c, &value);
- else
+ if (snd_mixer_selem_has_playback_channel(me, c)) {
+ if (e->db_fix) {
+ if ((r = snd_mixer_selem_get_playback_volume(me, c, &value)) >= 0) {
+ /* If the channel volume is outside the limits set
+ * by the dB fix, we clamp the hw volume to be
+ * within the limits. */
+ if (value < e->db_fix->min_step) {
+ value = e->db_fix->min_step;
+ snd_mixer_selem_set_playback_volume(me, c, value);
+ pa_log_debug("Playback volume for element %s channel %i was below the dB fix limit. "
+ "Volume reset to %0.2f dB.", e->alsa_name, c,
+ e->db_fix->db_values[value - e->db_fix->min_step] / 100.0);
+ } else if (value > e->db_fix->max_step) {
+ value = e->db_fix->max_step;
+ snd_mixer_selem_set_playback_volume(me, c, value);
+ pa_log_debug("Playback volume for element %s channel %i was over the dB fix limit. "
+ "Volume reset to %0.2f dB.", e->alsa_name, c,
+ e->db_fix->db_values[value - e->db_fix->min_step] / 100.0);
+ }
+
+ /* Volume step -> dB value conversion. */
+ value = e->db_fix->db_values[value - e->db_fix->min_step];
+ }
+ } else
+ r = snd_mixer_selem_get_playback_dB(me, c, &value);
+ } else
r = -1;
} else {
- if (snd_mixer_selem_has_capture_channel(me, c))
- r = snd_mixer_selem_get_capture_dB(me, c, &value);
- else
+ if (snd_mixer_selem_has_capture_channel(me, c)) {
+ if (e->db_fix) {
+ if ((r = snd_mixer_selem_get_capture_volume(me, c, &value)) >= 0) {
+ /* If the channel volume is outside the limits set
+ * by the dB fix, we clamp the hw volume to be
+ * within the limits. */
+ if (value < e->db_fix->min_step) {
+ value = e->db_fix->min_step;
+ snd_mixer_selem_set_capture_volume(me, c, value);
+ pa_log_debug("Capture volume for element %s channel %i was below the dB fix limit. "
+ "Volume reset to %0.2f dB.", e->alsa_name, c,
+ e->db_fix->db_values[value - e->db_fix->min_step] / 100.0);
+ } else if (value > e->db_fix->max_step) {
+ value = e->db_fix->max_step;
+ snd_mixer_selem_set_capture_volume(me, c, value);
+ pa_log_debug("Capture volume for element %s channel %i was over the dB fix limit. "
+ "Volume reset to %0.2f dB.", e->alsa_name, c,
+ e->db_fix->db_values[value - e->db_fix->min_step] / 100.0);
+ }
+
+ /* Volume step -> dB value conversion. */
+ value = e->db_fix->db_values[value - e->db_fix->min_step];
+ }
+ } else
+ r = snd_mixer_selem_get_capture_dB(me, c, &value);
+ } else
r = -1;
}
@@ -760,6 +818,37 @@ int pa_alsa_path_get_mute(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t *muted) {
return 0;
}
+/* Finds the closest item in db_fix->db_values and returns the corresponding
+ * step. *db_value is replaced with the value from the db_values table.
+ * Rounding is done based on the rounding parameter: -1 means rounding down and
+ * +1 means rounding up. */
+static long decibel_fix_get_step(pa_alsa_decibel_fix *db_fix, long *db_value, int rounding) {
+ unsigned i = 0;
+ unsigned max_i = 0;
+
+ pa_assert(db_fix);
+ pa_assert(db_value);
+ pa_assert(rounding != 0);
+
+ max_i = db_fix->max_step - db_fix->min_step;
+
+ if (rounding > 0) {
+ for (i = 0; i < max_i; i++) {
+ if (db_fix->db_values[i] >= *db_value)
+ break;
+ }
+ } else {
+ for (i = 0; i < max_i; i++) {
+ if (db_fix->db_values[i + 1] > *db_value)
+ break;
+ }
+ }
+
+ *db_value = db_fix->db_values[i];
+
+ return i + db_fix->min_step;
+}
+
static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v, pa_bool_t write_to_hw) {
snd_mixer_selem_id_t *sid;
@@ -804,31 +893,55 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
if (e->has_dB) {
long value = to_alsa_dB(f);
+ int rounding = value > 0 ? -1 : +1;
+
+ if (e->volume_limit >= 0 && value > (e->max_dB * 100))
+ value = e->max_dB * 100;
if (e->direction == PA_ALSA_DIRECTION_OUTPUT) {
- /* If we call set_play_volume() without checking first
- * if the channel is available, ALSA behaves ver
+ /* If we call set_playback_volume() without checking first
+ * if the channel is available, ALSA behaves very
* strangely and doesn't fail the call */
if (snd_mixer_selem_has_playback_channel(me, c)) {
- if (write_to_hw) {
- if ((r = snd_mixer_selem_set_playback_dB(me, c, value, +1)) >= 0)
- r = snd_mixer_selem_get_playback_dB(me, c, &value);
+ if (e->db_fix) {
+ if (write_to_hw)
+ r = snd_mixer_selem_set_playback_volume(me, c, decibel_fix_get_step(e->db_fix, &value, rounding));
+ else {
+ decibel_fix_get_step(e->db_fix, &value, rounding);
+ r = 0;
+ }
+
} else {
- long alsa_val;
- if ((r = snd_mixer_selem_ask_playback_dB_vol(me, value, +1, &alsa_val)) >= 0)
- r = snd_mixer_selem_ask_playback_vol_dB(me, alsa_val, &value);
+ if (write_to_hw) {
+ if ((r = snd_mixer_selem_set_playback_dB(me, c, value, rounding)) >= 0)
+ r = snd_mixer_selem_get_playback_dB(me, c, &value);
+ } else {
+ long alsa_val;
+ if ((r = snd_mixer_selem_ask_playback_dB_vol(me, value, rounding, &alsa_val)) >= 0)
+ r = snd_mixer_selem_ask_playback_vol_dB(me, alsa_val, &value);
+ }
}
} else
r = -1;
} else {
if (snd_mixer_selem_has_capture_channel(me, c)) {
- if (write_to_hw) {
- if ((r = snd_mixer_selem_set_capture_dB(me, c, value, +1)) >= 0)
- r = snd_mixer_selem_get_capture_dB(me, c, &value);
+ if (e->db_fix) {
+ if (write_to_hw)
+ r = snd_mixer_selem_set_capture_volume(me, c, decibel_fix_get_step(e->db_fix, &value, rounding));
+ else {
+ decibel_fix_get_step(e->db_fix, &value, rounding);
+ r = 0;
+ }
+
} else {
- long alsa_val;
- if ((r = snd_mixer_selem_ask_capture_dB_vol(me, value, +1, &alsa_val)) >= 0)
- r = snd_mixer_selem_ask_capture_vol_dB(me, alsa_val, &value);
+ if (write_to_hw) {
+ if ((r = snd_mixer_selem_set_capture_dB(me, c, value, rounding)) >= 0)
+ r = snd_mixer_selem_get_capture_dB(me, c, &value);
+ } else {
+ long alsa_val;
+ if ((r = snd_mixer_selem_ask_capture_dB_vol(me, value, rounding, &alsa_val)) >= 0)
+ r = snd_mixer_selem_ask_capture_vol_dB(me, alsa_val, &value);
+ }
}
} else
r = -1;
@@ -1012,9 +1125,19 @@ static int element_zero_volume(pa_alsa_element *e, snd_mixer_t *m) {
}
if (e->direction == PA_ALSA_DIRECTION_OUTPUT)
- r = snd_mixer_selem_set_playback_dB_all(me, 0, +1);
+ if (e->db_fix) {
+ long value = 0;
+
+ r = snd_mixer_selem_set_playback_volume_all(me, decibel_fix_get_step(e->db_fix, &value, +1));
+ } else
+ r = snd_mixer_selem_set_playback_dB_all(me, 0, +1);
else
- r = snd_mixer_selem_set_capture_dB_all(me, 0, +1);
+ if (e->db_fix) {
+ long value = 0;
+
+ r = snd_mixer_selem_set_capture_volume_all(me, decibel_fix_get_step(e->db_fix, &value, +1));
+ } else
+ r = snd_mixer_selem_set_capture_dB_all(me, 0, +1);
if (r < 0)
pa_log_warn("Failed to set volume to 0dB of %s: %s", e->alsa_name, pa_alsa_strerror(errno));
@@ -1121,6 +1244,40 @@ static int check_required(pa_alsa_element *e, snd_mixer_elem_t *me) {
if (e->required_absent == PA_ALSA_REQUIRED_ANY && (has_switch || has_volume || has_enumeration))
return -1;
+ if (e->required_any != PA_ALSA_REQUIRED_IGNORE) {
+ switch (e->required_any) {
+ case PA_ALSA_REQUIRED_VOLUME:
+ e->path->req_any_present |= (e->volume_use != PA_ALSA_VOLUME_IGNORE);
+ break;
+ case PA_ALSA_REQUIRED_SWITCH:
+ e->path->req_any_present |= (e->switch_use != PA_ALSA_SWITCH_IGNORE);
+ break;
+ case PA_ALSA_REQUIRED_ENUMERATION:
+ e->path->req_any_present |= (e->enumeration_use != PA_ALSA_ENUMERATION_IGNORE);
+ break;
+ case PA_ALSA_REQUIRED_ANY:
+ e->path->req_any_present |=
+ (e->volume_use != PA_ALSA_VOLUME_IGNORE) ||
+ (e->switch_use != PA_ALSA_SWITCH_IGNORE) ||
+ (e->enumeration_use != PA_ALSA_ENUMERATION_IGNORE);
+ break;
+ default:
+ pa_assert_not_reached();
+ }
+ }
+
+ if (e->enumeration_use == PA_ALSA_ENUMERATION_SELECT) {
+ pa_alsa_option *o;
+ PA_LLIST_FOREACH(o, e->options) {
+ e->path->req_any_present |= (o->required_any != PA_ALSA_REQUIRED_IGNORE) &&
+ (o->alsa_idx >= 0);
+ if (o->required != PA_ALSA_REQUIRED_IGNORE && o->alsa_idx < 0)
+ return -1;
+ if (o->required_absent != PA_ALSA_REQUIRED_IGNORE && o->alsa_idx >= 0)
+ return -1;
+ }
+ }
+
return 0;
}
@@ -1130,6 +1287,7 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
pa_assert(m);
pa_assert(e);
+ pa_assert(e->path);
SELEM_INIT(sid, e->alsa_name);
@@ -1197,26 +1355,6 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
e->direction_try_other = FALSE;
if (e->direction == PA_ALSA_DIRECTION_OUTPUT)
- e->has_dB = snd_mixer_selem_get_playback_dB_range(me, &min_dB, &max_dB) >= 0;
- else
- e->has_dB = snd_mixer_selem_get_capture_dB_range(me, &min_dB, &max_dB) >= 0;
-
- if (e->has_dB) {
-#ifdef HAVE_VALGRIND_MEMCHECK_H
- VALGRIND_MAKE_MEM_DEFINED(&min_dB, sizeof(min_dB));
- VALGRIND_MAKE_MEM_DEFINED(&max_dB, sizeof(max_dB));
-#endif
-
- e->min_dB = ((double) min_dB) / 100.0;
- e->max_dB = ((double) max_dB) / 100.0;
-
- if (min_dB >= max_dB) {
- pa_log_warn("Your kernel driver is broken: it reports a volume range from %0.2f dB to %0.2f dB which makes no sense.", e->min_dB, e->max_dB);
- e->has_dB = FALSE;
- }
- }
-
- if (e->direction == PA_ALSA_DIRECTION_OUTPUT)
r = snd_mixer_selem_get_playback_volume_range(me, &e->min_volume, &e->max_volume);
else
r = snd_mixer_selem_get_capture_volume_range(me, &e->min_volume, &e->max_volume);
@@ -1226,7 +1364,6 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
return -1;
}
-
if (e->min_volume >= e->max_volume) {
pa_log_warn("Your kernel driver is broken: it reports a volume range from %li to %li which makes no sense.", e->min_volume, e->max_volume);
e->volume_use = PA_ALSA_VOLUME_IGNORE;
@@ -1235,6 +1372,75 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
pa_bool_t is_mono;
pa_channel_position_t p;
+ if (e->db_fix &&
+ ((e->min_volume > e->db_fix->min_step) ||
+ (e->max_volume < e->db_fix->max_step))) {
+ pa_log_warn("The step range of the decibel fix for element %s (%li-%li) doesn't fit to the "
+ "real hardware range (%li-%li). Disabling the decibel fix.", e->alsa_name,
+ e->db_fix->min_step, e->db_fix->max_step,
+ e->min_volume, e->max_volume);
+
+ decibel_fix_free(e->db_fix);
+ e->db_fix = NULL;
+ }
+
+ if (e->db_fix) {
+ e->has_dB = TRUE;
+ e->min_volume = e->db_fix->min_step;
+ e->max_volume = e->db_fix->max_step;
+ min_dB = e->db_fix->db_values[0];
+ max_dB = e->db_fix->db_values[e->db_fix->max_step - e->db_fix->min_step];
+ } else if (e->direction == PA_ALSA_DIRECTION_OUTPUT)
+ e->has_dB = snd_mixer_selem_get_playback_dB_range(me, &min_dB, &max_dB) >= 0;
+ else
+ e->has_dB = snd_mixer_selem_get_capture_dB_range(me, &min_dB, &max_dB) >= 0;
+
+ if (e->has_dB) {
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+ VALGRIND_MAKE_MEM_DEFINED(&min_dB, sizeof(min_dB));
+ VALGRIND_MAKE_MEM_DEFINED(&max_dB, sizeof(max_dB));
+#endif
+
+ e->min_dB = ((double) min_dB) / 100.0;
+ e->max_dB = ((double) max_dB) / 100.0;
+
+ if (min_dB >= max_dB) {
+ pa_assert(!e->db_fix);
+ pa_log_warn("Your kernel driver is broken: it reports a volume range from %0.2f dB to %0.2f dB which makes no sense.", e->min_dB, e->max_dB);
+ e->has_dB = FALSE;
+ }
+ }
+
+ if (e->volume_limit >= 0) {
+ if (e->volume_limit <= e->min_volume || e->volume_limit > e->max_volume)
+ pa_log_warn("Volume limit for element %s of path %s is invalid: %li isn't within the valid range "
+ "%li-%li. The volume limit is ignored.",
+ e->alsa_name, e->path->name, e->volume_limit, e->min_volume + 1, e->max_volume);
+
+ else {
+ e->max_volume = e->volume_limit;
+
+ if (e->has_dB) {
+ if (e->db_fix) {
+ e->db_fix->max_step = e->max_volume;
+ e->max_dB = ((double) e->db_fix->db_values[e->db_fix->max_step - e->db_fix->min_step]) / 100.0;
+
+ } else {
+ if (e->direction == PA_ALSA_DIRECTION_OUTPUT)
+ r = snd_mixer_selem_ask_playback_vol_dB(me, e->max_volume, &max_dB);
+ else
+ r = snd_mixer_selem_ask_capture_vol_dB(me, e->max_volume, &max_dB);
+
+ if (r < 0) {
+ pa_log_warn("Failed to get dB value of %s: %s", e->alsa_name, pa_alsa_strerror(r));
+ e->has_dB = FALSE;
+ } else
+ e->max_dB = ((double) max_dB) / 100.0;
+ }
+ }
+ }
+ }
+
if (e->direction == PA_ALSA_DIRECTION_OUTPUT)
is_mono = snd_mixer_selem_is_playback_mono(me) > 0;
else
@@ -1293,9 +1499,6 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
}
- if (check_required(e, me) < 0)
- return -1;
-
if (e->switch_use == PA_ALSA_SWITCH_SELECT) {
pa_alsa_option *o;
@@ -1327,6 +1530,9 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
}
}
+ if (check_required(e, me) < 0)
+ return -1;
+
return 0;
}
@@ -1358,6 +1564,7 @@ static pa_alsa_element* element_get(pa_alsa_path *p, const char *section, pa_boo
e->path = p;
e->alsa_name = pa_xstrdup(section);
e->direction = p->direction;
+ e->volume_limit = -1;
PA_LLIST_INSERT_AFTER(pa_alsa_element, p->elements, p->last_element, e);
@@ -1581,20 +1788,23 @@ static int element_parse_required(
pa_alsa_path *p = userdata;
pa_alsa_element *e;
+ pa_alsa_option *o;
pa_alsa_required_t req;
pa_assert(p);
- if (!(e = element_get(p, section, TRUE))) {
+ e = element_get(p, section, TRUE);
+ o = option_get(p, section);
+ if (!e && !o) {
pa_log("[%s:%u] Required makes no sense in '%s'", filename, line, section);
return -1;
}
if (pa_streq(rvalue, "ignore"))
req = PA_ALSA_REQUIRED_IGNORE;
- else if (pa_streq(rvalue, "switch"))
+ else if (pa_streq(rvalue, "switch") && e)
req = PA_ALSA_REQUIRED_SWITCH;
- else if (pa_streq(rvalue, "volume"))
+ else if (pa_streq(rvalue, "volume") && e)
req = PA_ALSA_REQUIRED_VOLUME;
else if (pa_streq(rvalue, "enumeration"))
req = PA_ALSA_REQUIRED_ENUMERATION;
@@ -1605,10 +1815,28 @@ static int element_parse_required(
return -1;
}
- if (pa_streq(lvalue, "required-absent"))
- e->required_absent = req;
- else
- e->required = req;
+ if (pa_streq(lvalue, "required-absent")) {
+ if (e)
+ e->required_absent = req;
+ if (o)
+ o->required_absent = req;
+ }
+ else if (pa_streq(lvalue, "required-any")) {
+ if (e) {
+ e->required_any = req;
+ e->path->has_req_any = TRUE;
+ }
+ if (o) {
+ o->required_any = req;
+ o->element->path->has_req_any = TRUE;
+ }
+ }
+ else {
+ if (e)
+ e->required = req;
+ if (o)
+ o->required = req;
+ }
return 0;
}
@@ -1671,6 +1899,33 @@ static int element_parse_direction_try_other(
return 0;
}
+static int element_parse_volume_limit(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ pa_alsa_path *p = userdata;
+ pa_alsa_element *e;
+ uint32_t volume_limit;
+
+ if (!(e = element_get(p, section, TRUE))) {
+ pa_log("[%s:%u] volume-limit makes no sense in '%s'", filename, line, section);
+ return -1;
+ }
+
+ if (pa_atou(rvalue, &volume_limit) < 0 || volume_limit > LONG_MAX) {
+ pa_log("[%s:%u] Invalid value for volume-limit", filename, line);
+ return -1;
+ }
+
+ e->volume_limit = volume_limit;
+ return 0;
+}
+
static pa_channel_position_mask_t parse_mask(const char *m) {
pa_channel_position_mask_t v;
@@ -1804,8 +2059,11 @@ static int option_verify(pa_alsa_option *o) {
{ "input", N_("Input") },
{ "input-docking", N_("Docking Station Input") },
{ "input-docking-microphone", N_("Docking Station Microphone") },
+ { "input-docking-linein", N_("Docking Station Line-In") },
{ "input-linein", N_("Line-In") },
{ "input-microphone", N_("Microphone") },
+ { "input-microphone-front", N_("Front Microphone") },
+ { "input-microphone-rear", N_("Rear Microphone") },
{ "input-microphone-external", N_("External Microphone") },
{ "input-microphone-internal", N_("Internal Microphone") },
{ "input-radio", N_("Radio") },
@@ -1857,7 +2115,10 @@ static int element_verify(pa_alsa_element *e) {
pa_assert(e);
+// pa_log_debug("Element %s, path %s: r=%d, r-any=%d, r-abs=%d", e->alsa_name, e->path->name, e->required, e->required_any, e->required_absent);
if ((e->required != PA_ALSA_REQUIRED_IGNORE && e->required == e->required_absent) ||
+ (e->required_any != PA_ALSA_REQUIRED_IGNORE && e->required_any == e->required_absent) ||
+ (e->required_absent == PA_ALSA_REQUIRED_ANY && e->required_any != PA_ALSA_REQUIRED_IGNORE) ||
(e->required_absent == PA_ALSA_REQUIRED_ANY && e->required != PA_ALSA_REQUIRED_IGNORE)) {
pa_log("Element %s cannot be required and absent at the same time.", e->alsa_name);
return -1;
@@ -1879,6 +2140,10 @@ static int path_verify(pa_alsa_path *p) {
static const struct description_map well_known_descriptions[] = {
{ "analog-input", N_("Analog Input") },
{ "analog-input-microphone", N_("Analog Microphone") },
+ { "analog-input-microphone-front", N_("Front Microphone") },
+ { "analog-input-microphone-rear", N_("Rear Microphone") },
+ { "analog-input-microphone-dock", N_("Docking Station Microphone") },
+ { "analog-input-microphone-internal", N_("Internal Microphone") },
{ "analog-input-linein", N_("Analog Line-In") },
{ "analog-input-radio", N_("Analog Radio") },
{ "analog-input-video", N_("Analog Video") },
@@ -1934,9 +2199,11 @@ pa_alsa_path* pa_alsa_path_new(const char *fname, pa_alsa_direction_t direction)
{ "override-map.2", element_parse_override_map, NULL, NULL },
/* ... later on we might add override-map.3 and so on here ... */
{ "required", element_parse_required, NULL, NULL },
+ { "required-any", element_parse_required, NULL, NULL },
{ "required-absent", element_parse_required, NULL, NULL },
{ "direction", element_parse_direction, NULL, NULL },
{ "direction-try-other", element_parse_direction_try_other, NULL, NULL },
+ { "volume-limit", element_parse_volume_limit, NULL, NULL },
{ NULL, NULL, NULL, NULL }
};
@@ -1987,11 +2254,13 @@ pa_alsa_path* pa_alsa_path_synthesize(const char*element, pa_alsa_direction_t di
e->path = p;
e->alsa_name = pa_xstrdup(element);
e->direction = direction;
+ e->volume_limit = -1;
e->switch_use = PA_ALSA_SWITCH_MUTE;
e->volume_use = PA_ALSA_VOLUME_MERGE;
PA_LLIST_PREPEND(pa_alsa_element, p->elements, e);
+ p->last_element = e;
return p;
}
@@ -2131,6 +2400,7 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
pa_alsa_element *e;
double min_dB[PA_CHANNEL_POSITION_MAX], max_dB[PA_CHANNEL_POSITION_MAX];
pa_channel_position_t t;
+ pa_channel_position_mask_t path_volume_channels = 0;
pa_assert(p);
pa_assert(m);
@@ -2149,6 +2419,7 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
pa_log_debug("Probe of element '%s' failed.", e->alsa_name);
return -1;
}
+ pa_log_debug("Probe of element '%s' succeeded (volume=%d, switch=%d, enumeration=%d).", e->alsa_name, e->volume_use, e->switch_use, e->enumeration_use);
if (ignore_dB)
e->has_dB = FALSE;
@@ -2166,6 +2437,7 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
if (PA_CHANNEL_POSITION_MASK(t) & e->merged_mask) {
min_dB[t] = e->min_dB;
max_dB[t] = e->max_dB;
+ path_volume_channels |= PA_CHANNEL_POSITION_MASK(t);
}
p->has_dB = TRUE;
@@ -2176,17 +2448,21 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
if (PA_CHANNEL_POSITION_MASK(t) & e->merged_mask) {
min_dB[t] += e->min_dB;
max_dB[t] += e->max_dB;
+ path_volume_channels |= PA_CHANNEL_POSITION_MASK(t);
}
- } else
+ } else {
/* Hmm, there's another element before us
* which cannot do dB volumes, so we we need
* to 'neutralize' this slider */
e->volume_use = PA_ALSA_VOLUME_ZERO;
+ pa_log_info("Zeroing volume of '%s' on path '%s'", e->alsa_name, p->name);
+ }
}
- } else if (p->has_volume)
+ } else if (p->has_volume) {
/* We can't use this volume, so let's ignore it */
e->volume_use = PA_ALSA_VOLUME_IGNORE;
-
+ pa_log_info("Ignoring volume of '%s' on path '%s' (missing dB info)", e->alsa_name, p->name);
+ }
p->has_volume = TRUE;
}
@@ -2194,6 +2470,12 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
p->has_mute = TRUE;
}
+ if (p->has_req_any && !p->req_any_present) {
+ p->supported = FALSE;
+ pa_log_debug("Skipping path '%s', none of required-any elements preset.", p->name);
+ return -1;
+ }
+
path_drop_unsupported(p);
path_make_options_unique(p);
path_create_settings(p);
@@ -2205,11 +2487,13 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
p->max_dB = -INFINITY;
for (t = 0; t < PA_CHANNEL_POSITION_MAX; t++) {
- if (p->min_dB > min_dB[t])
- p->min_dB = min_dB[t];
+ if (path_volume_channels & PA_CHANNEL_POSITION_MASK(t)) {
+ if (p->min_dB > min_dB[t])
+ p->min_dB = min_dB[t];
- if (p->max_dB < max_dB[t])
- p->max_dB = max_dB[t];
+ if (p->max_dB < max_dB[t])
+ p->max_dB = max_dB[t];
+ }
}
return 0;
@@ -2239,13 +2523,15 @@ void pa_alsa_element_dump(pa_alsa_element *e) {
pa_alsa_option *o;
pa_assert(e);
- pa_log_debug("Element %s, direction=%i, switch=%i, volume=%i, enumeration=%i, required=%i, required_absent=%i, mask=0x%llx, n_channels=%u, override_map=%s",
+ pa_log_debug("Element %s, direction=%i, switch=%i, volume=%i, volume_limit=%li, enumeration=%i, required=%i, required_any=%i, required_absent=%i, mask=0x%llx, n_channels=%u, override_map=%s",
e->alsa_name,
e->direction,
e->switch_use,
e->volume_use,
+ e->volume_limit,
e->enumeration_use,
e->required,
+ e->required_any,
e->required_absent,
(long long unsigned) e->merged_mask,
e->n_channels,
@@ -2324,8 +2610,12 @@ void pa_alsa_path_set_set_callback(pa_alsa_path_set *ps, snd_mixer_t *m, snd_mix
pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t direction) {
pa_alsa_path_set *ps;
char **pn = NULL, **en = NULL, **ie;
+ pa_alsa_decibel_fix *db_fix;
+ void *state;
pa_assert(m);
+ pa_assert(m->profile_set);
+ pa_assert(m->profile_set->decibel_fixes);
pa_assert(direction == PA_ALSA_DIRECTION_OUTPUT || direction == PA_ALSA_DIRECTION_INPUT);
if (m->direction != PA_ALSA_DIRECTION_ANY && m->direction != direction)
@@ -2367,7 +2657,7 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
pa_xfree(fn);
}
- return ps;
+ goto finish;
}
if (direction == PA_ALSA_DIRECTION_OUTPUT)
@@ -2390,11 +2680,16 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
/* Mark all other passed elements for require-absent */
for (je = en; *je; je++) {
pa_alsa_element *e;
+
+ if (je == ie)
+ continue;
+
e = pa_xnew0(pa_alsa_element, 1);
e->path = p;
e->alsa_name = pa_xstrdup(*je);
e->direction = direction;
e->required_absent = PA_ALSA_REQUIRED_ANY;
+ e->volume_limit = -1;
PA_LLIST_INSERT_AFTER(pa_alsa_element, p->elements, p->last_element, e);
p->last_element = e;
@@ -2404,6 +2699,28 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
ps->last_path = p;
}
+finish:
+ /* Assign decibel fixes to elements. */
+ PA_HASHMAP_FOREACH(db_fix, m->profile_set->decibel_fixes, state) {
+ pa_alsa_path *p;
+
+ PA_LLIST_FOREACH(p, ps->paths) {
+ pa_alsa_element *e;
+
+ PA_LLIST_FOREACH(e, p->elements) {
+ if (e->volume_use != PA_ALSA_VOLUME_IGNORE && pa_streq(db_fix->name, e->alsa_name)) {
+ /* The profile set that contains the dB fix may be freed
+ * before the element, so we have to copy the dB fix
+ * object. */
+ e->db_fix = pa_xnewdup(pa_alsa_decibel_fix, db_fix, 1);
+ e->db_fix->profile_set = NULL;
+ e->db_fix->name = pa_xstrdup(db_fix->name);
+ e->db_fix->db_values = pa_xmemdup(db_fix->db_values, (db_fix->max_step - db_fix->min_step + 1) * sizeof(long));
+ }
+ }
+ }
+ }
+
return ps;
}
@@ -2580,6 +2897,15 @@ void pa_alsa_profile_set_free(pa_alsa_profile_set *ps) {
pa_hashmap_free(ps->mappings, NULL, NULL);
}
+ if (ps->decibel_fixes) {
+ pa_alsa_decibel_fix *db_fix;
+
+ while ((db_fix = pa_hashmap_steal_first(ps->decibel_fixes)))
+ decibel_fix_free(db_fix);
+
+ pa_hashmap_free(ps->decibel_fixes, NULL, NULL);
+ }
+
pa_xfree(ps);
}
@@ -2624,6 +2950,26 @@ static pa_alsa_profile *profile_get(pa_alsa_profile_set *ps, const char *name) {
return p;
}
+static pa_alsa_decibel_fix *decibel_fix_get(pa_alsa_profile_set *ps, const char *name) {
+ pa_alsa_decibel_fix *db_fix;
+
+ if (!pa_startswith(name, "DecibelFix "))
+ return NULL;
+
+ name += 11;
+
+ if ((db_fix = pa_hashmap_get(ps->decibel_fixes, name)))
+ return db_fix;
+
+ db_fix = pa_xnew0(pa_alsa_decibel_fix, 1);
+ db_fix->profile_set = ps;
+ db_fix->name = pa_xstrdup(name);
+
+ pa_hashmap_put(ps->decibel_fixes, db_fix->name, db_fix);
+
+ return db_fix;
+}
+
static int mapping_parse_device_strings(
const char *filename,
unsigned line,
@@ -2894,6 +3240,130 @@ static int profile_parse_skip_probe(
return 0;
}
+static int decibel_fix_parse_db_values(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ pa_alsa_profile_set *ps = userdata;
+ pa_alsa_decibel_fix *db_fix;
+ char **items;
+ char *item;
+ long *db_values;
+ unsigned n = 8; /* Current size of the db_values table. */
+ unsigned min_step = 0;
+ unsigned max_step = 0;
+ unsigned i = 0; /* Index to the items table. */
+ unsigned prev_step = 0;
+ double prev_db = 0;
+
+ pa_assert(filename);
+ pa_assert(section);
+ pa_assert(lvalue);
+ pa_assert(rvalue);
+ pa_assert(ps);
+
+ if (!(db_fix = decibel_fix_get(ps, section))) {
+ pa_log("[%s:%u] %s invalid in section %s", filename, line, lvalue, section);
+ return -1;
+ }
+
+ if (!(items = pa_split_spaces_strv(rvalue))) {
+ pa_log("[%s:%u] Value missing", pa_strnull(filename), line);
+ return -1;
+ }
+
+ db_values = pa_xnew(long, n);
+
+ while ((item = items[i++])) {
+ char *s = item; /* Step value string. */
+ char *d = item; /* dB value string. */
+ uint32_t step;
+ double db;
+
+ /* Move d forward until it points to a colon or to the end of the item. */
+ for (; *d && *d != ':'; ++d);
+
+ if (d == s) {
+ /* item started with colon. */
+ pa_log("[%s:%u] No step value found in %s", filename, line, item);
+ goto fail;
+ }
+
+ if (!*d || !*(d + 1)) {
+ /* No colon found, or it was the last character in item. */
+ pa_log("[%s:%u] No dB value found in %s", filename, line, item);
+ goto fail;
+ }
+
+ /* pa_atou() needs a null-terminating string. Let's replace the colon
+ * with a zero byte. */
+ *d++ = '\0';
+
+ if (pa_atou(s, &step) < 0) {
+ pa_log("[%s:%u] Invalid step value: %s", filename, line, s);
+ goto fail;
+ }
+
+ if (pa_atod(d, &db) < 0) {
+ pa_log("[%s:%u] Invalid dB value: %s", filename, line, d);
+ goto fail;
+ }
+
+ if (step <= prev_step && i != 1) {
+ pa_log("[%s:%u] Step value %u not greater than the previous value %u", filename, line, step, prev_step);
+ goto fail;
+ }
+
+ if (db < prev_db && i != 1) {
+ pa_log("[%s:%u] Decibel value %0.2f less than the previous value %0.2f", filename, line, db, prev_db);
+ goto fail;
+ }
+
+ if (i == 1) {
+ min_step = step;
+ db_values[0] = (long) (db * 100.0);
+ prev_step = step;
+ prev_db = db;
+ } else {
+ /* Interpolate linearly. */
+ double db_increment = (db - prev_db) / (step - prev_step);
+
+ for (; prev_step < step; ++prev_step, prev_db += db_increment) {
+
+ /* Reallocate the db_values table if it's about to overflow. */
+ if (prev_step + 1 - min_step == n) {
+ n *= 2;
+ db_values = pa_xrenew(long, db_values, n);
+ }
+
+ db_values[prev_step + 1 - min_step] = (long) ((prev_db + db_increment) * 100.0);
+ }
+ }
+
+ max_step = step;
+ }
+
+ db_fix->min_step = min_step;
+ db_fix->max_step = max_step;
+ pa_xfree(db_fix->db_values);
+ db_fix->db_values = db_values;
+
+ pa_xstrfreev(items);
+
+ return 0;
+
+fail:
+ pa_xstrfreev(items);
+ pa_xfree(db_values);
+
+ return -1;
+}
+
static int mapping_verify(pa_alsa_mapping *m, const pa_channel_map *bonus) {
static const struct description_map well_known_descriptions[] = {
@@ -2931,7 +3401,7 @@ static int mapping_verify(pa_alsa_mapping *m, const pa_channel_map *bonus) {
if ((m->input_path_names && m->input_element) ||
(m->output_path_names && m->output_element)) {
- pa_log("Mapping %s must have either mixer path or mixer elment, not both.", m->name);
+ pa_log("Mapping %s must have either mixer path or mixer element, not both.", m->name);
return -1;
}
@@ -3176,10 +3646,52 @@ void pa_alsa_profile_dump(pa_alsa_profile *p) {
pa_log_debug("Output %s", m->name);
}
+static int decibel_fix_verify(pa_alsa_decibel_fix *db_fix) {
+ pa_assert(db_fix);
+
+ /* Check that the dB mapping has been configured. Since "db-values" is
+ * currently the only option in the DecibelFix section, and decibel fix
+ * objects don't get created if a DecibelFix section is empty, this is
+ * actually a redundant check. Having this may prevent future bugs,
+ * however. */
+ if (!db_fix->db_values) {
+ pa_log("Decibel fix for element %s lacks the dB values.", db_fix->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+void pa_alsa_decibel_fix_dump(pa_alsa_decibel_fix *db_fix) {
+ char *db_values = NULL;
+
+ pa_assert(db_fix);
+
+ if (db_fix->db_values) {
+ pa_strbuf *buf;
+ long i;
+ long max_i = db_fix->max_step - db_fix->min_step;
+
+ buf = pa_strbuf_new();
+ pa_strbuf_printf(buf, "[%li]:%0.2f", db_fix->min_step, db_fix->db_values[0] / 100.0);
+
+ for (i = 1; i <= max_i; ++i)
+ pa_strbuf_printf(buf, " [%li]:%0.2f", i + db_fix->min_step, db_fix->db_values[i] / 100.0);
+
+ db_values = pa_strbuf_tostring_free(buf);
+ }
+
+ pa_log_debug("Decibel fix %s, min_step=%li, max_step=%li, db_values=%s",
+ db_fix->name, db_fix->min_step, db_fix->max_step, pa_strnull(db_values));
+
+ pa_xfree(db_values);
+}
+
pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel_map *bonus) {
pa_alsa_profile_set *ps;
pa_alsa_profile *p;
pa_alsa_mapping *m;
+ pa_alsa_decibel_fix *db_fix;
char *fn;
int r;
void *state;
@@ -3205,12 +3717,16 @@ pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel
{ "input-mappings", profile_parse_mappings, NULL, NULL },
{ "output-mappings", profile_parse_mappings, NULL, NULL },
{ "skip-probe", profile_parse_skip_probe, NULL, NULL },
+
+ /* [DecibelFix ...] */
+ { "db-values", decibel_fix_parse_db_values, NULL, NULL },
{ NULL, NULL, NULL, NULL }
};
ps = pa_xnew0(pa_alsa_profile_set, 1);
ps->mappings = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
ps->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+ ps->decibel_fixes = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
items[0].data = &ps->auto_profiles;
@@ -3240,6 +3756,10 @@ pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel
if (profile_verify(p) < 0)
goto fail;
+ PA_HASHMAP_FOREACH(db_fix, ps->decibel_fixes, state)
+ if (decibel_fix_verify(db_fix) < 0)
+ goto fail;
+
return ps;
fail:
@@ -3420,23 +3940,28 @@ void pa_alsa_profile_set_probe(
void pa_alsa_profile_set_dump(pa_alsa_profile_set *ps) {
pa_alsa_profile *p;
pa_alsa_mapping *m;
+ pa_alsa_decibel_fix *db_fix;
void *state;
pa_assert(ps);
- pa_log_debug("Profile set %p, auto_profiles=%s, probed=%s, n_mappings=%u, n_profiles=%u",
+ pa_log_debug("Profile set %p, auto_profiles=%s, probed=%s, n_mappings=%u, n_profiles=%u, n_decibel_fixes=%u",
(void*)
ps,
pa_yes_no(ps->auto_profiles),
pa_yes_no(ps->probed),
pa_hashmap_size(ps->mappings),
- pa_hashmap_size(ps->profiles));
+ pa_hashmap_size(ps->profiles),
+ pa_hashmap_size(ps->decibel_fixes));
PA_HASHMAP_FOREACH(m, ps->mappings, state)
pa_alsa_mapping_dump(m);
PA_HASHMAP_FOREACH(p, ps->profiles, state)
pa_alsa_profile_dump(p);
+
+ PA_HASHMAP_FOREACH(db_fix, ps->decibel_fixes, state)
+ pa_alsa_decibel_fix_dump(db_fix);
}
void pa_alsa_add_ports(pa_hashmap **p, pa_alsa_path_set *ps) {
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 7fb408a6..c24a8965 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -46,6 +46,7 @@ typedef struct pa_alsa_path pa_alsa_path;
typedef struct pa_alsa_path_set pa_alsa_path_set;
typedef struct pa_alsa_mapping pa_alsa_mapping;
typedef struct pa_alsa_profile pa_alsa_profile;
+typedef struct pa_alsa_decibel_fix pa_alsa_decibel_fix;
typedef struct pa_alsa_profile_set pa_alsa_profile_set;
typedef struct pa_alsa_port_data pa_alsa_port_data;
@@ -112,11 +113,15 @@ struct pa_alsa_option {
char *name;
char *description;
unsigned priority;
+
+ pa_alsa_required_t required;
+ pa_alsa_required_t required_any;
+ pa_alsa_required_t required_absent;
};
-/* And element wraps one specific ALSA element. A series of elements *
-make up a path (see below). If the element is an enumeration or switch
-* element it may includes a list of options. */
+/* An element wraps one specific ALSA element. A series of elements
+ * make up a path (see below). If the element is an enumeration or switch
+ * element it may include a list of options. */
struct pa_alsa_element {
pa_alsa_path *path;
PA_LLIST_FIELDS(pa_alsa_element);
@@ -129,6 +134,7 @@ struct pa_alsa_element {
pa_alsa_enumeration_use_t enumeration_use;
pa_alsa_required_t required;
+ pa_alsa_required_t required_any;
pa_alsa_required_t required_absent;
pa_bool_t override_map:1;
@@ -136,6 +142,7 @@ struct pa_alsa_element {
pa_bool_t has_dB:1;
long min_volume, max_volume;
+ long volume_limit; /* -1 for no configured limit */
double min_dB, max_dB;
pa_channel_position_mask_t masks[SND_MIXER_SCHN_LAST][2];
@@ -144,6 +151,8 @@ struct pa_alsa_element {
pa_channel_position_mask_t merged_mask;
PA_LLIST_HEAD(pa_alsa_option, options);
+
+ pa_alsa_decibel_fix *db_fix;
};
/* A path wraps a series of elements into a single entity which can be
@@ -164,6 +173,9 @@ struct pa_alsa_path {
pa_bool_t has_mute:1;
pa_bool_t has_volume:1;
pa_bool_t has_dB:1;
+ /* These two are used during probing only */
+ pa_bool_t has_req_any:1;
+ pa_bool_t req_any_present:1;
long min_volume, max_volume;
double min_dB, max_dB;
@@ -258,9 +270,26 @@ struct pa_alsa_profile {
pa_idxset *output_mappings;
};
+struct pa_alsa_decibel_fix {
+ pa_alsa_profile_set *profile_set;
+
+ char *name; /* Alsa volume element name. */
+ long min_step;
+ long max_step;
+
+ /* An array that maps alsa volume element steps to decibels. The steps can
+ * be used as indices to this array, after substracting min_step from the
+ * real value.
+ *
+ * The values are actually stored as integers representing millibels,
+ * because that's the format the alsa API uses. */
+ long *db_values;
+};
+
struct pa_alsa_profile_set {
pa_hashmap *mappings;
pa_hashmap *profiles;
+ pa_hashmap *decibel_fixes;
pa_bool_t auto_profiles;
pa_bool_t probed:1;
@@ -268,6 +297,7 @@ struct pa_alsa_profile_set {
void pa_alsa_mapping_dump(pa_alsa_mapping *m);
void pa_alsa_profile_dump(pa_alsa_profile *p);
+void pa_alsa_decibel_fix_dump(pa_alsa_decibel_fix *db_fix);
pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel_map *bonus);
void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, const pa_sample_spec *ss, unsigned default_n_fragments, unsigned default_fragment_size_msec);
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 45a7af39..6d18e607 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -796,7 +796,7 @@ static void update_smoother(struct userdata *u) {
}
static pa_usec_t source_get_latency(struct userdata *u) {
- int64_t delay;
+ int64_t delay;
pa_usec_t now1, now2;
pa_assert(u);
diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index 786e664d..6435db00 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -362,7 +362,7 @@ int pa_alsa_set_hw_params(
pa_log_debug("Set neither period nor buffer size.");
/* Last chance, set nothing */
- if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
+ if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret));
goto finish;
}
diff --git a/src/modules/alsa/mixer/paths/analog-input-dock-mic.conf b/src/modules/alsa/mixer/paths/analog-input-dock-mic.conf
new file mode 100644
index 00000000..74826a96
--- /dev/null
+++ b/src/modules/alsa/mixer/paths/analog-input-dock-mic.conf
@@ -0,0 +1,81 @@
+# This file is part of PulseAudio.
+#
+# PulseAudio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
+#
+# PulseAudio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with PulseAudio; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+; For devices where a 'Dock Mic' or 'Dock Mic Boost' element exists
+;
+; See analog-output.conf.common for an explanation on the directives
+
+[General]
+priority = 80
+name = analog-input-microphone-dock
+
+[Element Dock Mic Boost]
+required-any = any
+switch = select
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Option Dock Mic Boost:on]
+name = input-boost-on
+
+[Option Dock Mic Boost:off]
+name = input-boost-off
+
+[Element Dock Mic]
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Capture]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Input Source]
+enumeration = select
+
+[Option Input Source:Dock Mic]
+name = analog-input-microphone-dock
+required-any = any
+
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Dock Mic]
+name = analog-input-microphone-dock
+required-any = any
+
+[Element Mic]
+switch = off
+volume = off
+
+[Element Internal Mic]
+switch = off
+volume = off
+
+[Element Front Mic]
+switch = off
+volume = off
+
+[Element Rear Mic]
+switch = off
+volume = off
+
+.include analog-input-mic.conf.common
diff --git a/src/modules/alsa/mixer/paths/analog-input-front-mic.conf b/src/modules/alsa/mixer/paths/analog-input-front-mic.conf
new file mode 100644
index 00000000..6c58ece1
--- /dev/null
+++ b/src/modules/alsa/mixer/paths/analog-input-front-mic.conf
@@ -0,0 +1,81 @@
+# This file is part of PulseAudio.
+#
+# PulseAudio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
+#
+# PulseAudio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with PulseAudio; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+; For devices where a 'Front Mic' or 'Front Mic Boost' element exists
+;
+; See analog-output.conf.common for an explanation on the directives
+
+[General]
+priority = 90
+name = analog-input-microphone-front
+
+[Element Front Mic Boost]
+required-any = any
+switch = select
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Option Front Mic Boost:on]
+name = input-boost-on
+
+[Option Front Mic Boost:off]
+name = input-boost-off
+
+[Element Front Mic]
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Capture]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Input Source]
+enumeration = select
+
+[Option Input Source:Front Mic]
+name = analog-input-microphone-front
+required-any = any
+
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Front Mic]
+name = analog-input-microphone-front
+required-any = any
+
+[Element Mic]
+switch = off
+volume = off
+
+[Element Internal Mic]
+switch = off
+volume = off
+
+[Element Rear Mic]
+switch = off
+volume = off
+
+[Element Dock Mic]
+switch = off
+volume = off
+
+.include analog-input-mic.conf.common
diff --git a/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf b/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf
index 70cd5129..70a1cd12 100644
--- a/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf
+++ b/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf
@@ -14,54 +14,98 @@
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-; For devices where a 'Internal Mic' element exists
+; For devices where a 'Internal Mic' or 'Internal Mic Boost' element exists
+; 'Int Mic' and 'Int Mic Boost' are for compatibility with kernels < 2.6.38
;
; See analog-output.conf.common for an explanation on the directives
[General]
-priority = 90
-name = analog-input-microphone
+priority = 89
+name = analog-input-microphone-internal
-[Element Capture]
-switch = mute
+[Element Internal Mic Boost]
+required-any = any
+switch = select
volume = merge
override-map.1 = all
override-map.2 = all-left,all-right
-[Element Mic]
-switch = off
-volume = off
+[Option Internal Mic Boost:on]
+name = input-boost-on
+
+[Option Internal Mic Boost:off]
+name = input-boost-off
+
+[Element Int Mic Boost]
+required-any = any
+switch = select
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Option Int Mic Boost:on]
+name = input-boost-on
+
+[Option Int Mic Boost:off]
+name = input-boost-off
+
[Element Internal Mic]
-required = any
+required-any = any
switch = mute
volume = merge
override-map.1 = all
override-map.2 = all-left,all-right
-[Element Line]
-switch = off
-volume = off
+[Element Int Mic]
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
-[Element Aux]
-switch = off
-volume = off
+[Element Capture]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Input Source]
+enumeration = select
+
+[Option Input Source:Internal Mic]
+name = analog-input-microphone-internal
+required-any = any
+
+[Option Input Source:Int Mic]
+name = analog-input-microphone-internal
+required-any = any
-[Element Video]
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Internal Mic]
+name = analog-input-microphone-internal
+required-any = any
+
+[Option Capture Source:Int Mic]
+name = analog-input-microphone-internal
+required-any = any
+
+[Element Mic]
switch = off
volume = off
-[Element Mic/Line]
+[Element Dock Mic]
switch = off
volume = off
-[Element TV Tuner]
+[Element Front Mic]
switch = off
volume = off
-[Element FM]
+[Element Rear Mic]
switch = off
volume = off
-.include analog-input.conf.common
.include analog-input-mic.conf.common
diff --git a/src/modules/alsa/mixer/paths/analog-input-linein.conf b/src/modules/alsa/mixer/paths/analog-input-linein.conf
index 57568ccd..461cebdb 100644
--- a/src/modules/alsa/mixer/paths/analog-input-linein.conf
+++ b/src/modules/alsa/mixer/paths/analog-input-linein.conf
@@ -35,13 +35,35 @@ volume = off
switch = off
volume = off
+[Element Line Boost]
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
[Element Line]
-required = any
+required-any = any
switch = mute
volume = merge
override-map.1 = all
override-map.2 = all-left,all-right
+[Element Input Source]
+enumeration = select
+
+[Option Input Source:Line]
+name = analog-input-linein
+required-any = any
+
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Line]
+name = analog-input-linein
+required-any = any
+
+
[Element Aux]
switch = off
volume = off
@@ -62,4 +84,10 @@ volume = off
switch = off
volume = off
-.include analog-input.conf.common
+[Element Mic Jack Mode]
+enumeration = select
+
+[Option Mic Jack Mode:Line In]
+priority = 19
+required-any = any
+name = input-linein
diff --git a/src/modules/alsa/mixer/paths/analog-input-mic.conf b/src/modules/alsa/mixer/paths/analog-input-mic.conf
index 9b8b75a1..d88028bf 100644
--- a/src/modules/alsa/mixer/paths/analog-input-mic.conf
+++ b/src/modules/alsa/mixer/paths/analog-input-mic.conf
@@ -14,54 +14,91 @@
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-; For devices where a 'Mic' element exists
+; For devices where a 'Mic' or 'Mic Boost' element exists
;
; See analog-output.conf.common for an explanation on the directives
[General]
-priority = 100
+priority = 89
name = analog-input-microphone
-[Element Capture]
-switch = mute
+[Element Mic Boost]
+required-any = any
+switch = select
volume = merge
override-map.1 = all
override-map.2 = all-left,all-right
+[Option Mic Boost:on]
+name = input-boost-on
+
+[Option Mic Boost:off]
+name = input-boost-off
+
[Element Mic]
-required = any
+required-any = any
switch = mute
volume = merge
override-map.1 = all
override-map.2 = all-left,all-right
-[Element Internal Mic]
-switch = off
-volume = off
+[Element Capture]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
-[Element Line]
-switch = off
-volume = off
+[Element Input Source]
+enumeration = select
-[Element Aux]
-switch = off
-volume = off
+[Option Input Source:Mic]
+name = analog-input-microphone
+required-any = any
+
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Mic]
+name = analog-input-microphone
+required-any = any
+
+;;; Some AC'97s have "Mic Select" and "Mic Boost (+20dB)"
+
+[Element Mic Select]
+enumeration = select
-[Element Video]
+[Option Mic Select:Mic1]
+name = input-microphone
+priority = 20
+
+[Option Mic Select:Mic2]
+name = input-microphone
+priority = 19
+
+[Element Mic Boost (+20dB)]
+switch = select
+volume = merge
+
+[Option Mic Boost (+20dB):on]
+name = input-boost-on
+
+[Option Mic Boost (+20dB):off]
+name = input-boost-off
+
+[Element Front Mic]
switch = off
volume = off
-[Element Mic/Line]
+[Element Internal Mic]
switch = off
volume = off
-[Element TV Tuner]
+[Element Rear Mic]
switch = off
volume = off
-[Element FM]
+[Element Dock Mic]
switch = off
volume = off
-.include analog-input.conf.common
.include analog-input-mic.conf.common
diff --git a/src/modules/alsa/mixer/paths/analog-input-mic.conf.common b/src/modules/alsa/mixer/paths/analog-input-mic.conf.common
index 9bddd48c..2e4f0d81 100644
--- a/src/modules/alsa/mixer/paths/analog-input-mic.conf.common
+++ b/src/modules/alsa/mixer/paths/analog-input-mic.conf.common
@@ -18,64 +18,37 @@
;
; See analog-output.conf.common for an explanation on the directives
-;;; 'Mic Select'
+[Element Line]
+switch = off
+volume = off
-[Element Mic Select]
-enumeration = select
-
-[Option Mic Select:Mic1]
-name = input-microphone
-priority = 20
-
-[Option Mic Select:Mic2]
-name = input-microphone
-priority = 19
-
-;;; Various Boosts
-
-[Element Mic Boost (+20dB)]
-switch = select
-volume = merge
-
-[Option Mic Boost (+20dB):on]
-name = input-boost-on
+[Element Line Boost]
+switch = off
+volume = off
-[Option Mic Boost (+20dB):off]
-name = input-boost-off
+[Element Aux]
+switch = off
+volume = off
-[Element Mic Boost]
-switch = select
-volume = merge
+[Element Video]
+switch = off
+volume = off
-[Option Mic Boost:on]
-name = input-boost-on
+[Element Mic/Line]
+switch = off
+volume = off
-[Option Mic Boost:off]
-name = input-boost-off
+[Element TV Tuner]
+switch = off
+volume = off
-[Element Front Mic Boost]
-switch = select
+[Element FM]
+switch = off
+volume = off
-[Option Front Mic Boost:on]
-name = input-boost-on
-
-[Option Front Mic Boost:off]
-name = input-boost-off
-
-[Element Rear Mic Boost]
-switch = select
-
-[Option Rear Mic Boost:on]
-name = input-boost-on
-
-[Option Rear Mic Boost:off]
-name = input-boost-off
-
-[Element Int Mic Boost]
-switch = select
-
-[Option Int Mic Boost:on]
-name = input-boost-on
+[Element Mic Jack Mode]
+enumeration = select
-[Option Int Mic Boost:off]
-name = input-boost-off
+[Option Mic Jack Mode:Mic In]
+priority = 19
+name = input-microphone
diff --git a/src/modules/alsa/mixer/paths/analog-input-rear-mic.conf b/src/modules/alsa/mixer/paths/analog-input-rear-mic.conf
new file mode 100644
index 00000000..75ed61b0
--- /dev/null
+++ b/src/modules/alsa/mixer/paths/analog-input-rear-mic.conf
@@ -0,0 +1,81 @@
+# This file is part of PulseAudio.
+#
+# PulseAudio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
+#
+# PulseAudio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with PulseAudio; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+; For devices where a 'Rear Mic' or 'Rear Mic Boost' element exists
+;
+; See analog-output.conf.common for an explanation on the directives
+
+[General]
+priority = 89
+name = analog-input-microphone-rear
+
+[Element Rear Mic Boost]
+required-any = any
+switch = select
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Option Rear Mic Boost:on]
+name = input-boost-on
+
+[Option Rear Mic Boost:off]
+name = input-boost-off
+
+[Element Rear Mic]
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Capture]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Input Source]
+enumeration = select
+
+[Option Input Source:Rear Mic]
+name = analog-input-microphone-rear
+required-any = any
+
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Rear Mic]
+name = analog-input-microphone-rear
+required-any = any
+
+[Element Mic]
+switch = off
+volume = off
+
+[Element Internal Mic]
+switch = off
+volume = off
+
+[Element Front Mic]
+switch = off
+volume = off
+
+[Element Dock Mic]
+switch = off
+volume = off
+
+.include analog-input-mic.conf.common
diff --git a/src/modules/alsa/mixer/paths/analog-input.conf b/src/modules/alsa/mixer/paths/analog-input.conf
index 30507386..b86c3564 100644
--- a/src/modules/alsa/mixer/paths/analog-input.conf
+++ b/src/modules/alsa/mixer/paths/analog-input.conf
@@ -32,9 +32,36 @@ override-map.2 = all-left,all-right
[Element Mic]
required-absent = any
+[Element Dock Mic]
+required-absent = any
+
+[Element Dock Mic Boost]
+required-absent = any
+
+[Element Front Mic]
+required-absent = any
+
+[Element Front Mic Boost]
+required-absent = any
+
+[Element Int Mic]
+required-absent = any
+
+[Element Int Mic Boost]
+required-absent = any
+
[Element Internal Mic]
required-absent = any
+[Element Internal Mic Boost]
+required-absent = any
+
+[Element Rear Mic]
+required-absent = any
+
+[Element Rear Mic Boost]
+required-absent = any
+
[Element Line]
required-absent = any
@@ -54,4 +81,3 @@ required-absent = any
required-absent = any
.include analog-input.conf.common
-.include analog-input-mic.conf.common
diff --git a/src/modules/alsa/mixer/paths/analog-input.conf.common b/src/modules/alsa/mixer/paths/analog-input.conf.common
index 0b2cfd94..94165776 100644
--- a/src/modules/alsa/mixer/paths/analog-input.conf.common
+++ b/src/modules/alsa/mixer/paths/analog-input.conf.common
@@ -66,42 +66,18 @@ enumeration = select
name = input-microphone
priority = 20
-[Option Input Source:Mic]
-name = input-microphone
-priority = 20
-
[Option Input Source:Microphone]
name = input-microphone
priority = 20
-[Option Input Source:Front Mic]
-name = input-microphone
-priority = 19
-
[Option Input Source:Front Microphone]
name = input-microphone
priority = 19
-[Option Input Source:Int Mic]
-name = input-microphone
-priority = 19
-
-[Option Input Source:Internal Mic]
-name = input-microphone
-priority = 19
-
-[Option Input Source:Rear Mic]
-name = input-microphone
-priority = 19
-
[Option Input Source:Internal Mic 1]
name = input-microphone
priority = 19
-[Option Input Source:Line]
-name = input-linein
-priority = 18
-
[Option Input Source:Line-In]
name = input-linein
priority = 18
@@ -135,21 +111,12 @@ name = input
[Option Capture Source:Line/Mic]
name = input
-[Option Capture Source:Mic]
-name = input-microphone
-
[Option Capture Source:Microphone]
name = input-microphone
-[Option Capture Source:Int Mic]
-name = input-microphone-internal
-
[Option Capture Source:Int DMic]
name = input-microphone-internal
-[Option Capture Source:Internal Mic]
-name = input-microphone-internal
-
[Option Capture Source:iMic]
name = input-microphone-internal
@@ -159,15 +126,9 @@ name = input-microphone-internal
[Option Capture Source:Internal Microphone]
name = input-microphone-internal
-[Option Capture Source:Front Mic]
-name = input-microphone
-
[Option Capture Source:Front Microphone]
name = input-microphone
-[Option Capture Source:Rear Mic]
-name = input-microphone
-
[Option Capture Source:Mic1]
name = input-microphone
@@ -198,9 +159,6 @@ name = input-linein
[Option Capture Source:Analog]
name = input
-[Option Capture Source:Line]
-name = input-linein
-
[Option Capture Source:Line-In]
name = input-linein
@@ -261,9 +219,6 @@ name = input
[Option Capture Source:Docking-Station]
name = input-docking
-[Option Capture Source:Dock Mic]
-name = input-docking-microphone
-
;;; 'Mic Jack Mode'
[Element Mic Jack Mode]
diff --git a/src/modules/alsa/mixer/paths/analog-output.conf.common b/src/modules/alsa/mixer/paths/analog-output.conf.common
index 6131da5c..c7c44350 100644
--- a/src/modules/alsa/mixer/paths/analog-output.conf.common
+++ b/src/modules/alsa/mixer/paths/analog-output.conf.common
@@ -63,10 +63,15 @@
; # by the option name, resp. on/off if the element is a switch.
; name = ... # Logical name to use in the path identifier
; priority = ... # Priority if this is made into a device port
+; required = ignore | enumeration | any # In this element, this option must exist or the path will be invalid. ("any" is an alias for "enumeration".)
+; required-any = ignore | enumeration | any # In this element, either this or another option must exist (or an element)
+; required-absent = ignore | enumeration | any # In this element, this option must not exist or the path will be invalid
;
; [Element ...] # For each element that we shall control
; required = ignore | switch | volume | enumeration | any # If set, require this element to be of this kind and available,
; # otherwise don't consider this path valid for the card
+; required-any = ignore | switch | volume | enumeration | any # If set, at least one of the elements with required-any in this
+; # path must be present, otherwise this path is invalid for the card
; required-absent = ignore | switch | volume # If set, require this element to not be of this kind and not
; # available, otherwise don't consider this path valid for the card
;
@@ -77,6 +82,7 @@
; volume = ignore | merge | off | zero # What to do with this volume: ignore it, merge it into the device
; # volume slider, always set it to the lowest value possible, or always
; # set it to 0 dB (for whatever that means)
+; volume-limit = <volume step> # Limit the maximum volume by disabling the volume steps above <volume step>.
; enumeration = ignore | select # What to do with this enumeration, ignore it or make it selectable
; # via device ports. If set to 'select' you need to define an Option section
; # for each of the items you want to expose
diff --git a/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules b/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules
index f964b005..03293409 100644
--- a/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules
+++ b/src/modules/alsa/mixer/profile-sets/90-pulseaudio.rules
@@ -24,6 +24,8 @@ SUBSYSTEMS=="usb", ATTRS{idVendor}=="17cc", ATTRS{idProduct}=="1978", ENV{PULSE_
SUBSYSTEMS=="usb", ATTRS{idVendor}=="17cc", ATTRS{idProduct}=="0839", ENV{PULSE_PROFILE_SET}="native-instruments-audio4dj.conf"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="17cc", ATTRS{idProduct}=="baff", ENV{PULSE_PROFILE_SET}="native-instruments-traktorkontrol-s4.conf"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="17cc", ATTRS{idProduct}=="4711", ENV{PULSE_PROFILE_SET}="native-instruments-korecontroller.conf"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="17cc", ATTRS{idProduct}=="1011", ENV{PULSE_PROFILE_SET}="native-instruments-traktor-audio6.conf"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="17cc", ATTRS{idProduct}=="1021", ENV{PULSE_PROFILE_SET}="native-instruments-traktor-audio10.conf"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0763", ATTRS{idProduct}=="2012", ENV{PULSE_PROFILE_SET}="maudio-fasttrack-pro.conf"
LABEL="pulseaudio_end"
diff --git a/src/modules/alsa/mixer/profile-sets/default.conf b/src/modules/alsa/mixer/profile-sets/default.conf
index f470d604..9f7b5f2b 100644
--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -16,17 +16,27 @@
; Default profile definitions for the ALSA backend of PulseAudio. This
; is used as fallback for all cards that have no special mapping
-; assigned. (and should be good enough for the vast majority of
-; cards). Use the udev property PULSE_PROFILE_SET to assign a
-; different profile set than this one to a device. So what is this
-; about? Simply, what we do here is map ALSA devices to how they are
-; exposed in PA. We say which ALSA device string to use to open a
-; device, which channel mapping to use then, and which mixer path to
-; use. This is encoded in a 'mapping'. Multiple of these mappings can
-; be bound together in a 'profile' which is then directly exposed in
-; the UI as a card profile. Each mapping assigned to a profile will
-; result in one sink/source to be created if the profile is selected
-; for the card.
+; assigned (and should be good enough for the vast majority of
+; cards). If you want to assign a different profile set than this one
+; to a device, either set the udev property PULSE_PROFILE_SET for the
+; card, or use the "profile_set" module argument when loading
+; module-alsa-card.
+;
+; So what is this about? Simply, what we do here is map ALSA devices
+; to how they are exposed in PA. We say which ALSA device string to
+; use to open a device, which channel mapping to use then, and which
+; mixer path to use. This is encoded in a 'mapping'. Multiple of these
+; mappings can be bound together in a 'profile' which is then directly
+; exposed in the UI as a card profile. Each mapping assigned to a
+; profile will result in one sink/source to be created if the profile
+; is selected for the card.
+;
+; Additionally, the path set configuration files can describe the
+; decibel values assigned to the steps of the volume elements. This
+; can be used to work around situations when the alsa driver doesn't
+; provide any decibel information, or when the information is
+; incorrect.
+
; [General]
; auto-profiles = no | yes # Instead of defining all profiles manually, autogenerate
@@ -55,6 +65,35 @@
; skip-probe = no | yes # Skip probing for availability? If this is yes then this profile
; # will be assumed as working without probing. Makes initialization
; # a bit faster but only works if the card is really known well.
+;
+; [DecibelFix element] # Decibel fixes can be used to work around missing or incorrect dB
+; # information from alsa. A decibel fix is a table that maps volume steps
+; # to decibel values for one volume element. The "element" part in the
+; # section title is the name of the volume element.
+; #
+; # NOTE: This feature is meant just as a help for figuring out the correct
+; # decibel values. Pulseaudio is not the correct place to maintain the
+; # decibel mappings!
+; #
+; # If you need this feature, then you should make sure that when you have
+; # the correct values figured out, the alsa driver developers get informed
+; # too, so that they can fix the driver.
+;
+; db-values = ... # The option value consists of pairs of step numbers and decibel values.
+; # The pairs are separated with whitespace, and steps are separated from
+; # the corresponding decibel values with a colon. The values must be in an
+; # increasing order. Here's an example of a valid string:
+; #
+; # "0:-40.50 1:-38.70 3:-33.00 11:0"
+; #
+; # The lowest step imposes a lower limit for hardware volume and the
+; # highest step correspondingly imposes a higher limit. That means that
+; # that the mixer will never be set outside those values - the rest of the
+; # volume scale is done using software volume.
+; #
+; # As can be seen in the example, you don't need to specify a dB value for
+; # each step. The dB values for skipped steps will be linearly interpolated
+; # using the nearest steps that are given.
[General]
auto-profiles = yes
@@ -63,14 +102,14 @@ auto-profiles = yes
device-strings = hw:%f
channel-map = mono
paths-output = analog-output analog-output-speaker analog-output-desktop-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono analog-output-lfe-on-mono
-paths-input = analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line
+paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line
priority = 1
[Mapping analog-stereo]
device-strings = front:%f hw:%f
channel-map = left,right
paths-output = analog-output analog-output-speaker analog-output-desktop-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono analog-output-lfe-on-mono
-paths-input = analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line
+paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line
priority = 10
[Mapping analog-surround-40]
diff --git a/src/modules/alsa/mixer/profile-sets/native-instruments-traktor-audio10.conf b/src/modules/alsa/mixer/profile-sets/native-instruments-traktor-audio10.conf
new file mode 100644
index 00000000..4deb65da
--- /dev/null
+++ b/src/modules/alsa/mixer/profile-sets/native-instruments-traktor-audio10.conf
@@ -0,0 +1,131 @@
+# This file is part of PulseAudio.
+#
+# PulseAudio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
+#
+# PulseAudio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with PulseAudio; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+; Native Instruments Audio 10 DJ
+;
+; This card has five stereo pairs of input and five stereo pairs of
+; output
+;
+; We knowingly only define a subset of the theoretically possible
+; mapping combinations as profiles here.
+;
+; See default.conf for an explanation on the directives used here.
+
+[General]
+auto-profiles = no
+
+[Mapping analog-stereo-out-main]
+description = Analog Stereo Main
+device-strings = hw:%f,0,0
+channel-map = left,right
+
+[Mapping analog-stereo-out-a]
+description = Analog Stereo Channel A
+device-strings = hw:%f,0,1
+channel-map = left,right
+direction = output
+
+[Mapping analog-stereo-out-b]
+description = Analog Stereo Channel B
+device-strings = hw:%f,0,1
+channel-map = left,right
+direction = output
+
+[Mapping analog-stereo-out-c]
+description = Analog Stereo Channel C
+device-strings = hw:%f,0,2
+channel-map = left,right
+direction = output
+
+[Mapping analog-stereo-out-d]
+description = Analog Stereo Channel D
+device-strings = hw:%f,0,3
+channel-map = left,right
+direction = output
+
+[Mapping analog-stereo-in-main]
+description = Analog Stereo Main
+device-strings = hw:%f,0,0
+channel-map = left,right
+
+[Mapping analog-stereo-in-a]
+description = Analog Stereo Channel A
+device-strings = hw:%f,0,1
+channel-map = left,right
+direction = input
+
+[Mapping analog-stereo-in-b]
+description = Analog Stereo Channel B
+device-strings = hw:%f,0,1
+channel-map = left,right
+direction = input
+
+[Mapping analog-stereo-in-c]
+description = Analog Stereo Channel C
+device-strings = hw:%f,0,2
+channel-map = left,right
+direction = input
+
+[Mapping analog-stereo-in-d]
+description = Analog Stereo Channel D
+device-strings = hw:%f,0,3
+channel-map = left,right
+direction = input
+
+
+
+
+[Profile output:analog-stereo-all+input:analog-stereo-all]
+description = Analog Stereo Duplex Channels Main, A, B, C, D
+output-mappings = analog-stereo-out-main analog-stereo-out-a analog-stereo-out-b analog-stereo-out-c analog-stereo-out-d
+input-mappings = analog-stereo-in-main analog-stereo-in-a analog-stereo-in-b analog-stereo-in-c analog-stereo-in-d
+priority = 100
+skip-probe = yes
+
+[Profile output:analog-stereo-main+input:analog-stereo-main]
+description = Analog Stereo Duplex Main
+output-mappings = analog-stereo-out-main
+input-mappings = analog-stereo-in-main
+priority = 50
+skip-probe = yes
+
+[Profile output:analog-stereo-a+input:analog-stereo-a]
+description = Analog Stereo Duplex Channel A
+output-mappings = analog-stereo-out-a
+input-mappings = analog-stereo-in-a
+priority = 40
+skip-probe = yes
+
+[Profile output:analog-stereo-b+input:analog-stereo-b]
+description = Analog Stereo Duplex Channel B
+output-mappings = analog-stereo-out-b
+input-mappings = analog-stereo-in-b
+priority = 30
+skip-probe = yes
+
+[Profile output:analog-stereo-a+input:analog-stereo-c]
+description = Analog Stereo Duplex Channel C
+output-mappings = analog-stereo-out-c
+input-mappings = analog-stereo-in-c
+priority = 20
+skip-probe = yes
+
+[Profile output:analog-stereo-a+input:analog-stereo-d]
+description = Analog Stereo Duplex Channel D
+output-mappings = analog-stereo-out-d
+input-mappings = analog-stereo-in-d
+priority = 10
+skip-probe = yes
diff --git a/src/modules/alsa/mixer/profile-sets/native-instruments-traktor-audio6.conf b/src/modules/alsa/mixer/profile-sets/native-instruments-traktor-audio6.conf
new file mode 100644
index 00000000..48d9058b
--- /dev/null
+++ b/src/modules/alsa/mixer/profile-sets/native-instruments-traktor-audio6.conf
@@ -0,0 +1,92 @@
+# This file is part of PulseAudio.
+#
+# PulseAudio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
+#
+# PulseAudio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with PulseAudio; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+; Native Instruments Audio 6 DJ
+;
+; This card has three stereo pairs of input and three stereo pairs of
+; output
+;
+; We knowingly only define a subset of the theoretically possible
+; mapping combinations as profiles here.
+;
+; See default.conf for an explanation on the directives used here.
+
+[General]
+auto-profiles = no
+
+[Mapping analog-stereo-out-main]
+description = Analog Stereo Main
+device-strings = hw:%f,0,0
+channel-map = left,right
+
+[Mapping analog-stereo-out-a]
+description = Analog Stereo Channel A
+device-strings = hw:%f,0,1
+channel-map = left,right
+direction = output
+
+[Mapping analog-stereo-out-b]
+description = Analog Stereo Channel B
+device-strings = hw:%f,0,1
+channel-map = left,right
+direction = output
+
+[Mapping analog-stereo-in-main]
+description = Analog Stereo Main
+device-strings = hw:%f,0,0
+channel-map = left,right
+
+[Mapping analog-stereo-in-a]
+description = Analog Stereo Channel A
+device-strings = hw:%f,0,1
+channel-map = left,right
+direction = input
+
+[Mapping analog-stereo-in-b]
+description = Analog Stereo Channel B
+device-strings = hw:%f,0,1
+channel-map = left,right
+direction = input
+
+
+
+[Profile output:analog-stereo-all+input:analog-stereo-all]
+description = Analog Stereo Duplex Channels A, B (Headphones)
+output-mappings = analog-stereo-out-main analog-stereo-out-a analog-stereo-out-b
+input-mappings = analog-stereo-in-main analog-stereo-in-a analog-stereo-in-b
+priority = 100
+skip-probe = yes
+
+[Profile output:analog-stereo-main+input:analog-stereo-main]
+description = Analog Stereo Duplex Channel Main
+output-mappings = analog-stereo-out-main
+input-mappings = analog-stereo-in-main
+priority = 50
+skip-probe = yes
+
+[Profile output:analog-stereo-a+input:analog-stereo-a]
+description = Analog Stereo Duplex Channel A
+output-mappings = analog-stereo-out-a
+input-mappings = analog-stereo-in-a
+priority = 40
+skip-probe = yes
+
+[Profile output:analog-stereo-b+input:analog-stereo-b]
+description = Analog Stereo Duplex Channel B
+output-mappings = analog-stereo-out-b
+input-mappings = analog-stereo-in-b
+priority = 30
+skip-probe = yes
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index ebd2f8ae..e60aa5ef 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -65,7 +65,8 @@ PA_MODULE_USAGE(
"tsched_buffer_watermark=<lower fill watermark> "
"profile=<profile name> "
"ignore_dB=<ignore dB information from the device?> "
- "sync_volume=<syncronize sw and hw voluchanges in IO-thread?>");
+ "sync_volume=<syncronize sw and hw voluchanges in IO-thread?> "
+ "profile_set=<profile set configuration file> ");
static const char* const valid_modargs[] = {
"name",
@@ -88,6 +89,7 @@ static const char* const valid_modargs[] = {
"profile",
"ignore_dB",
"sync_volume",
+ "profile_set",
NULL
};
@@ -328,6 +330,11 @@ int pa__init(pa_module *m) {
fn = pa_udev_get_property(alsa_card_index, "PULSE_PROFILE_SET");
#endif
+ if (pa_modargs_get_value(ma, "profile_set", NULL)) {
+ pa_xfree(fn);
+ fn = pa_xstrdup(pa_modargs_get_value(ma, "profile_set", NULL));
+ }
+
u->profile_set = pa_alsa_profile_set_new(fn, &u->core->default_channel_map);
pa_xfree(fn);
@@ -335,6 +342,7 @@ int pa__init(pa_module *m) {
goto fail;
pa_alsa_profile_set_probe(u->profile_set, u->device_id, &m->core->default_sample_spec, m->core->default_n_fragments, m->core->default_fragment_size_msec);
+ pa_alsa_profile_set_dump(u->profile_set);
pa_card_new_data_init(&data);
data.driver = __FILE__;
@@ -393,6 +401,14 @@ int pa__init(pa_module *m) {
if (reserve)
pa_reserve_wrapper_unref(reserve);
+ if (!pa_hashmap_isempty(u->profile_set->decibel_fixes))
+ pa_log_warn("Card %s uses decibel fixes (i.e. overrides the decibel information for some alsa volume elements). "
+ "Please note that this feature is meant just as a help for figuring out the correct decibel values. "
+ "Pulseaudio is not the correct place to maintain the decibel mappings! The fixed decibel values "
+ "should be sent to ALSA developers so that they can fix the driver. If it turns out that this feature "
+ "is abused (i.e. fixes are not pushed to ALSA), the decibel fix feature may be removed in some future "
+ "Pulseaudio version.", u->card->name);
+
return 0;
fail:
diff --git a/src/modules/alsa/module-alsa-sink.c b/src/modules/alsa/module-alsa-sink.c
index 697fab45..465c8b9e 100644
--- a/src/modules/alsa/module-alsa-sink.c
+++ b/src/modules/alsa/module-alsa-sink.c
@@ -40,7 +40,8 @@ PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
"name=<name of the sink, to be prefixed> "
"sink_name=<name for the sink> "
- "sink_properities=<properties for the sink> "
+ "sink_properties=<properties for the sink> "
+ "namereg_fail=<pa_namereg_register() fail parameter value> "
"device=<ALSA device> "
"device_id=<ALSA card index> "
"format=<sample format> "
@@ -64,6 +65,7 @@ static const char* const valid_modargs[] = {
"name",
"sink_name",
"sink_properties",
+ "namereg_fail",
"device",
"device_id",
"format",
diff --git a/src/modules/alsa/module-alsa-source.c b/src/modules/alsa/module-alsa-source.c
index 23da4185..90ffea57 100644
--- a/src/modules/alsa/module-alsa-source.c
+++ b/src/modules/alsa/module-alsa-source.c
@@ -65,6 +65,7 @@ PA_MODULE_USAGE(
"name=<name for the source, to be prefixed> "
"source_name=<name for the source> "
"source_properties=<properties for the source> "
+ "namereg_fail=<pa_namereg_register() fail parameter value> "
"device=<ALSA device> "
"device_id=<ALSA card index> "
"format=<sample format> "
@@ -84,6 +85,7 @@ static const char* const valid_modargs[] = {
"name",
"source_name",
"source_properties",
+ "namereg_fail",
"device",
"device_id",
"format",
diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index 47e0fd50..293e0244 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -193,7 +193,7 @@ static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device
dbus_message_iter_get_basic(i, &key);
- if (!dbus_message_iter_next(i)) {
+ if (!dbus_message_iter_next(i)) {
pa_log("Property value missing");
return -1;
}
@@ -323,7 +323,7 @@ static int parse_audio_property(pa_bluetooth_discovery *u, int *state, DBusMessa
dbus_message_iter_get_basic(i, &key);
- if (!dbus_message_iter_next(i)) {
+ if (!dbus_message_iter_next(i)) {
pa_log("Property value missing");
return -1;
}
@@ -590,7 +590,7 @@ static void list_devices_reply(DBusPendingCall *pending, void *userdata) {
finish:
if (paths)
- dbus_free_string_array (paths);
+ dbus_free_string_array(paths);
dbus_message_unref(r);
@@ -598,8 +598,7 @@ finish:
pa_dbus_pending_free(p);
}
-static void register_endpoint(pa_bluetooth_discovery *y, const char *path, const char *endpoint, const char *uuid)
-{
+static void register_endpoint(pa_bluetooth_discovery *y, const char *path, const char *endpoint, const char *uuid) {
DBusMessage *m;
DBusMessageIter i, d;
uint8_t codec = 0;
@@ -699,7 +698,7 @@ static void list_adapters_reply(DBusPendingCall *pending, void *userdata) {
finish:
if (paths)
- dbus_free_string_array (paths);
+ dbus_free_string_array(paths);
dbus_message_unref(r);
@@ -715,6 +714,47 @@ static void list_adapters(pa_bluetooth_discovery *y) {
send_and_add_to_pending(y, NULL, m, list_adapters_reply);
}
+int pa_bluetooth_transport_parse_property(pa_bluetooth_transport *t, DBusMessageIter *i)
+{
+ const char *key;
+ DBusMessageIter variant_i;
+
+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
+ pa_log("Property name not a string.");
+ return -1;
+ }
+
+ dbus_message_iter_get_basic(i, &key);
+
+ if (!dbus_message_iter_next(i)) {
+ pa_log("Property value missing");
+ return -1;
+ }
+
+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
+ pa_log("Property value not a variant.");
+ return -1;
+ }
+
+ dbus_message_iter_recurse(i, &variant_i);
+
+ switch (dbus_message_iter_get_arg_type(&variant_i)) {
+
+ case DBUS_TYPE_BOOLEAN: {
+
+ pa_bool_t *value;
+ dbus_message_iter_get_basic(&variant_i, &value);
+
+ if (pa_streq(key, "NREC"))
+ t->nrec = value;
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *userdata) {
DBusError err;
pa_bluetooth_discovery *y;
@@ -863,6 +903,28 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ } else if (dbus_message_is_signal(m, "org.bluez.MediaTransport", "PropertyChanged")) {
+ pa_bluetooth_device *d;
+ pa_bluetooth_transport *t;
+ void *state = NULL;
+ DBusMessageIter arg_i;
+
+ while ((d = pa_hashmap_iterate(y->devices, &state, NULL)))
+ if ((t = pa_hashmap_get(d->transports, dbus_message_get_path(m))))
+ break;
+
+ if (!t)
+ goto fail;
+
+ if (!dbus_message_iter_init(m, &arg_i)) {
+ pa_log("Failed to parse PropertyChanged: %s", err.message);
+ goto fail;
+ }
+
+ if (pa_bluetooth_transport_parse_property(t, &arg_i) < 0)
+ goto fail;
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
fail:
@@ -935,10 +997,11 @@ const pa_bluetooth_transport* pa_bluetooth_device_get_transport(const pa_bluetoo
return NULL;
}
-int pa_bluetooth_transport_acquire(const pa_bluetooth_transport *t, const char *accesstype) {
+int pa_bluetooth_transport_acquire(const pa_bluetooth_transport *t, const char *accesstype, size_t *imtu, size_t *omtu) {
DBusMessage *m, *r;
DBusError err;
int ret;
+ uint16_t i, o;
pa_assert(t);
pa_assert(t->y);
@@ -956,7 +1019,7 @@ int pa_bluetooth_transport_acquire(const pa_bluetooth_transport *t, const char *
}
#ifdef DBUS_TYPE_UNIX_FD
- if (!dbus_message_get_args(r, &err, DBUS_TYPE_UNIX_FD, &ret, DBUS_TYPE_INVALID)) {
+ if (!dbus_message_get_args(r, &err, DBUS_TYPE_UNIX_FD, &ret, DBUS_TYPE_UINT16, &i, DBUS_TYPE_UINT16, &o, DBUS_TYPE_INVALID)) {
pa_log("Failed to parse org.bluez.MediaTransport.Acquire(): %s", err.message);
ret = -1;
dbus_error_free(&err);
@@ -964,6 +1027,12 @@ int pa_bluetooth_transport_acquire(const pa_bluetooth_transport *t, const char *
}
#endif
+ if (imtu)
+ *imtu = i;
+
+ if (omtu)
+ *omtu = o;
+
fail:
dbus_message_unref(r);
return ret;
@@ -1029,6 +1098,7 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
const char *path, *dev_path = NULL, *uuid = NULL;
uint8_t *config = NULL;
int size = 0;
+ pa_bool_t nrec;
enum profile p;
DBusMessageIter args, props;
DBusMessage *r;
@@ -1064,6 +1134,10 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
if (var != DBUS_TYPE_OBJECT_PATH)
goto fail;
dbus_message_iter_get_basic(&value, &dev_path);
+ } else if (strcasecmp(key, "NREC") == 0) {
+ if (var != DBUS_TYPE_BOOLEAN)
+ goto fail;
+ dbus_message_iter_get_basic(&value, &nrec);
} else if (strcasecmp(key, "Configuration") == 0) {
DBusMessageIter array;
if (var != DBUS_TYPE_ARRAY)
@@ -1087,6 +1161,8 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
p = PROFILE_A2DP_SOURCE;
t = transport_new(y, path, p, config, size);
+ if (nrec)
+ t->nrec = nrec;
pa_hashmap_put(d->transports, t->path, t);
pa_log_debug("Transport %s profile %d available", t->path, t->profile);
@@ -1396,6 +1472,7 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {
"type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'",
+ "type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'",
NULL) < 0) {
pa_log("Failed to add D-Bus matches: %s", err.message);
goto fail;
@@ -1463,6 +1540,7 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {
"type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'",
+ "type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'",
NULL);
if (y->filter_added)
diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h
index f141209d..bb0cb24a 100644
--- a/src/modules/bluetooth/bluetooth-util.h
+++ b/src/modules/bluetooth/bluetooth-util.h
@@ -70,6 +70,7 @@ struct pa_bluetooth_transport {
uint8_t codec;
uint8_t *config;
int config_size;
+ pa_bool_t nrec;
};
/* This enum is shared among Audio, Headset, AudioSink, and AudioSource, although not all values are acceptable in all profiles */
@@ -126,8 +127,9 @@ const pa_bluetooth_device* pa_bluetooth_discovery_get_by_address(pa_bluetooth_di
const pa_bluetooth_transport* pa_bluetooth_discovery_get_transport(pa_bluetooth_discovery *y, const char *path);
const pa_bluetooth_transport* pa_bluetooth_device_get_transport(const pa_bluetooth_device *d, enum profile profile);
-int pa_bluetooth_transport_acquire(const pa_bluetooth_transport *t, const char *accesstype);
+int pa_bluetooth_transport_acquire(const pa_bluetooth_transport *t, const char *accesstype, size_t *imtu, size_t *omtu);
void pa_bluetooth_transport_release(const pa_bluetooth_transport *t, const char *accesstype);
+int pa_bluetooth_transport_parse_property(pa_bluetooth_transport *t, DBusMessageIter *i);
pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *d);
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index dc09ffca..55610546 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -58,6 +58,9 @@
#define MAX_BITPOOL 64
#define MIN_BITPOOL 2U
+#define BITPOOL_DEC_LIMIT 32
+#define BITPOOL_DEC_STEP 5
+
PA_MODULE_AUTHOR("Joao Paulo Rechi Vita");
PA_MODULE_DESCRIPTION("Bluetooth audio sink and source");
PA_MODULE_VERSION(PACKAGE_VERSION);
@@ -117,6 +120,8 @@ struct a2dp_info {
size_t buffer_size; /* Size of the buffer */
uint16_t seq_num; /* Cumulative packet sequence */
+ uint8_t min_bitpool;
+ uint8_t max_bitpool;
};
struct hsp_info {
@@ -574,7 +579,7 @@ static int setup_a2dp(struct userdata *u) {
}
/* Run from main thread */
-static void setup_sbc(struct a2dp_info *a2dp) {
+static void setup_sbc(struct a2dp_info *a2dp, enum profile p) {
sbc_capabilities_t *active_capabilities;
pa_assert(a2dp);
@@ -660,7 +665,11 @@ static void setup_sbc(struct a2dp_info *a2dp) {
pa_assert_not_reached();
}
- a2dp->sbc.bitpool = active_capabilities->max_bitpool;
+ a2dp->min_bitpool = active_capabilities->min_bitpool;
+ a2dp->max_bitpool = active_capabilities->max_bitpool;
+
+ /* Set minimum bitpool for source to get the maximum possible block_size */
+ a2dp->sbc.bitpool = p == PROFILE_A2DP ? a2dp->max_bitpool : a2dp->min_bitpool;
a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc);
}
@@ -728,7 +737,7 @@ static int set_conf(struct userdata *u) {
/* setup SBC encoder now we agree on parameters */
if (u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE) {
- setup_sbc(&u->a2dp);
+ setup_sbc(&u->a2dp, u->profile);
u->block_size =
((u->link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
@@ -743,6 +752,39 @@ static int set_conf(struct userdata *u) {
return 0;
}
+/* from IO thread */
+static void a2dp_set_bitpool(struct userdata *u, uint8_t bitpool)
+{
+ struct a2dp_info *a2dp;
+
+ pa_assert(u);
+
+ a2dp = &u->a2dp;
+
+ if (a2dp->sbc.bitpool == bitpool)
+ return;
+
+ if (bitpool > a2dp->max_bitpool)
+ bitpool = a2dp->max_bitpool;
+ else if (bitpool < a2dp->min_bitpool)
+ bitpool = a2dp->min_bitpool;
+
+ a2dp->sbc.bitpool = bitpool;
+
+ a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
+ a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc);
+
+ pa_log_debug("Bitpool has changed to %u", a2dp->sbc.bitpool);
+
+ u->block_size =
+ (u->link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
+ / a2dp->frame_length * a2dp->codesize;
+
+ pa_sink_set_max_request_within_thread(u->sink, u->block_size);
+ pa_sink_set_fixed_latency_within_thread(u->sink,
+ FIXED_LATENCY_PLAYBACK_A2DP + pa_bytes_to_usec(u->block_size, &u->sample_spec));
+}
+
/* from IO thread, except in SCO over PCM */
static int setup_stream(struct userdata *u) {
@@ -758,6 +800,9 @@ static int setup_stream(struct userdata *u) {
pa_log_debug("Stream properly set up, we're ready to roll!");
+ if (u->profile == PROFILE_A2DP)
+ a2dp_set_bitpool(u, u->a2dp.max_bitpool);
+
u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
pollfd->fd = u->stream_fd;
@@ -857,8 +902,7 @@ static int stop_stream_fd(struct userdata *u) {
return r;
}
-static void bt_transport_release(struct userdata *u)
-{
+static void bt_transport_release(struct userdata *u) {
const char *accesstype = "rw";
const pa_bluetooth_transport *t;
@@ -891,8 +935,7 @@ static void bt_transport_release(struct userdata *u)
}
}
-static int bt_transport_acquire(struct userdata *u, pa_bool_t start)
-{
+static int bt_transport_acquire(struct userdata *u, pa_bool_t start) {
const char *accesstype = "rw";
const pa_bluetooth_transport *t;
@@ -912,7 +955,8 @@ static int bt_transport_acquire(struct userdata *u, pa_bool_t start)
return -1;
}
- u->stream_fd = pa_bluetooth_transport_acquire(t, accesstype);
+ /* FIXME: Handle in/out MTU properly when unix socket is not longer supported */
+ u->stream_fd = pa_bluetooth_transport_acquire(t, accesstype, NULL, &u->link_mtu);
if (u->stream_fd < 0)
return -1;
@@ -1351,7 +1395,7 @@ static int a2dp_process_render(struct userdata *u) {
break;
pa_log_error("Failed to write data to socket: %s", pa_cstrerror(errno));
- ret = -1;
+ ret = -1;
break;
}
@@ -1443,7 +1487,7 @@ static int a2dp_process_push(struct userdata *u) {
d = pa_memblock_acquire(memchunk.memblock);
to_write = memchunk.length = pa_memblock_get_length(memchunk.memblock);
- while (PA_LIKELY(to_decode > 0 && to_write > 0)) {
+ while (PA_LIKELY(to_decode > 0)) {
size_t written;
ssize_t decoded;
@@ -1462,10 +1506,12 @@ static int a2dp_process_push(struct userdata *u) {
/* pa_log_debug("SBC: decoded: %lu; written: %lu", (unsigned long) decoded, (unsigned long) written); */
/* pa_log_debug("SBC: frame_length: %lu; codesize: %lu", (unsigned long) a2dp->frame_length, (unsigned long) a2dp->codesize); */
+ /* Reset frame length, it can be changed due to bitpool change */
+ a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc);
+
pa_assert_fp((size_t) decoded <= to_decode);
pa_assert_fp((size_t) decoded == a2dp->frame_length);
- pa_assert_fp((size_t) written <= to_write);
pa_assert_fp((size_t) written == a2dp->codesize);
p = (const uint8_t*) p + decoded;
@@ -1477,6 +1523,8 @@ static int a2dp_process_push(struct userdata *u) {
frame_count++;
}
+ memchunk.length -= to_write;
+
pa_memblock_release(memchunk.memblock);
pa_source_post(u->source, &memchunk);
@@ -1490,6 +1538,27 @@ static int a2dp_process_push(struct userdata *u) {
return ret;
}
+static void a2dp_reduce_bitpool(struct userdata *u)
+{
+ struct a2dp_info *a2dp;
+ uint8_t bitpool;
+
+ pa_assert(u);
+
+ a2dp = &u->a2dp;
+
+ /* Check if bitpool is already at its limit */
+ if (a2dp->sbc.bitpool <= BITPOOL_DEC_LIMIT)
+ return;
+
+ bitpool = a2dp->sbc.bitpool - BITPOOL_DEC_STEP;
+
+ if (bitpool < BITPOOL_DEC_LIMIT)
+ bitpool = BITPOOL_DEC_LIMIT;
+
+ a2dp_set_bitpool(u, bitpool);
+}
+
static void thread_func(void *userdata) {
struct userdata *u = userdata;
unsigned do_write = 0;
@@ -1581,6 +1650,9 @@ static void thread_func(void *userdata) {
pa_sink_render_full(u->sink, skip_bytes, &tmp);
pa_memblock_unref(tmp.memblock);
u->write_index += skip_bytes;
+
+ if (u->profile == PROFILE_A2DP)
+ a2dp_reduce_bitpool(u);
}
}
@@ -1679,8 +1751,8 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
dbus_message_get_path(m),
dbus_message_get_member(m));
- if (!dbus_message_has_path(m, u->path))
- goto fail;
+ if (!dbus_message_has_path(m, u->path) && !dbus_message_has_path(m, u->transport))
+ goto fail;
if (dbus_message_is_signal(m, "org.bluez.Headset", "SpeakerGainChanged") ||
dbus_message_is_signal(m, "org.bluez.Headset", "MicrophoneGainChanged")) {
@@ -1705,6 +1777,28 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
pa_source_volume_changed(u->source, &v);
}
}
+ } else if (dbus_message_is_signal(m, "org.bluez.MediaTransport", "PropertyChanged")) {
+ DBusMessageIter arg_i;
+ pa_bluetooth_transport *t;
+ pa_bool_t nrec;
+
+ t = (pa_bluetooth_transport *) pa_bluetooth_discovery_get_transport(u->discovery, u->transport);
+ pa_assert(t);
+
+ if (!dbus_message_iter_init(m, &arg_i)) {
+ pa_log("Failed to parse PropertyChanged: %s", err.message);
+ goto fail;
+ }
+
+ nrec = t->nrec;
+
+ if (pa_bluetooth_transport_parse_property(t, &arg_i) < 0)
+ goto fail;
+
+ if (nrec != t->nrec) {
+ pa_log_debug("dbus: property 'NREC' changed to value '%s'", t->nrec ? "True" : "False");
+ pa_proplist_sets(u->source->proplist, "bluetooth.nrec", t->nrec ? "1" : "0");
+ }
}
fail:
@@ -1946,6 +2040,7 @@ static int add_source(struct userdata *u) {
pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP_SOURCE ? "a2dp_source" : "hsp");
if ((u->profile == PROFILE_HSP) || (u->profile == PROFILE_HFGW))
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
+
data.card = u->card;
data.name = get_name("source", u->modargs, u->address, &b);
data.namereg_fail = b;
@@ -1972,8 +2067,15 @@ static int add_source(struct userdata *u) {
pa_bytes_to_usec(u->block_size, &u->sample_spec));
}
- if (u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW)
- pa_proplist_sets(u->source->proplist, "bluetooth.nrec", (u->hsp.pcm_capabilities.flags & BT_PCM_FLAG_NREC) ? "1" : "0");
+ if ((u->profile == PROFILE_HSP) || (u->profile == PROFILE_HFGW)) {
+ if (u->transport) {
+ const pa_bluetooth_transport *t;
+ t = pa_bluetooth_discovery_get_transport(u->discovery, u->transport);
+ pa_assert(t);
+ pa_proplist_sets(u->source->proplist, "bluetooth.nrec", t->nrec ? "1" : "0");
+ } else
+ pa_proplist_sets(u->source->proplist, "bluetooth.nrec", (u->hsp.pcm_capabilities.flags & BT_PCM_FLAG_NREC) ? "1" : "0");
+ }
if (u->profile == PROFILE_HSP) {
u->source->set_volume = source_set_volume_cb;
@@ -2007,8 +2109,7 @@ static void shutdown_bt(struct userdata *u) {
}
}
-static int bt_transport_config_a2dp(struct userdata *u)
-{
+static int bt_transport_config_a2dp(struct userdata *u) {
const pa_bluetooth_transport *t;
struct a2dp_info *a2dp = &u->a2dp;
sbc_capabilities_raw_t *config;
@@ -2097,7 +2198,11 @@ static int bt_transport_config_a2dp(struct userdata *u)
pa_assert_not_reached();
}
- a2dp->sbc.bitpool = config->max_bitpool;
+ a2dp->min_bitpool = config->min_bitpool;
+ a2dp->max_bitpool = config->max_bitpool;
+
+ /* Set minimum bitpool for source to get the maximum possible block_size */
+ a2dp->sbc.bitpool = u->profile == PROFILE_A2DP ? a2dp->max_bitpool : a2dp->min_bitpool;
a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc);
@@ -2112,8 +2217,7 @@ static int bt_transport_config_a2dp(struct userdata *u)
return 0;
}
-static int bt_transport_config(struct userdata *u)
-{
+static int bt_transport_config(struct userdata *u) {
if (u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW) {
u->block_size = u->link_mtu;
return 0;
@@ -2122,101 +2226,12 @@ static int bt_transport_config(struct userdata *u)
return bt_transport_config_a2dp(u);
}
-static int parse_transport_property(struct userdata *u, DBusMessageIter *i)
-{
- const char *key;
- DBusMessageIter variant_i;
-
- pa_assert(u);
- pa_assert(i);
-
- if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
- pa_log("Property name not a string.");
- return -1;
- }
-
- dbus_message_iter_get_basic(i, &key);
-
- if (!dbus_message_iter_next(i)) {
- pa_log("Property value missing");
- return -1;
- }
-
- if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
- pa_log("Property value not a variant.");
- return -1;
- }
-
- dbus_message_iter_recurse(i, &variant_i);
-
- switch (dbus_message_iter_get_arg_type(&variant_i)) {
-
- case DBUS_TYPE_UINT16: {
-
- uint16_t value;
- dbus_message_iter_get_basic(&variant_i, &value);
-
- if (pa_streq(key, "OMTU"))
- u->link_mtu = value;
-
- break;
- }
-
- }
-
- return 0;
-}
-
/* Run from main thread */
-static int bt_transport_open(struct userdata *u)
-{
- DBusMessage *m, *r;
- DBusMessageIter arg_i, element_i;
- DBusError err;
-
+static int bt_transport_open(struct userdata *u) {
if (bt_transport_acquire(u, FALSE) < 0)
return -1;
- dbus_error_init(&err);
-
- pa_assert_se(m = dbus_message_new_method_call("org.bluez", u->transport, "org.bluez.MediaTransport", "GetProperties"));
- r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->connection), m, -1, &err);
-
- if (dbus_error_is_set(&err) || !r) {
- pa_log("Failed to get transport properties: %s", err.message);
- goto fail;
- }
-
- if (!dbus_message_iter_init(r, &arg_i)) {
- pa_log("GetProperties reply has no arguments.");
- goto fail;
- }
-
- if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
- pa_log("GetProperties argument is not an array.");
- goto fail;
- }
-
- dbus_message_iter_recurse(&arg_i, &element_i);
- while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
-
- if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
- DBusMessageIter dict_i;
-
- dbus_message_iter_recurse(&element_i, &dict_i);
-
- parse_transport_property(u, &dict_i);
- }
-
- if (!dbus_message_iter_next(&element_i))
- break;
- }
-
return bt_transport_config(u);
-
-fail:
- dbus_message_unref(r);
- return -1;
}
/* Run from main thread */
@@ -2696,7 +2711,7 @@ int pa__init(pa_module* m) {
struct userdata *u;
const char *address, *path;
DBusError err;
- char *mike, *speaker;
+ char *mike, *speaker, *transport;
const pa_bluetooth_device *device;
pa_assert(m);
@@ -2775,15 +2790,18 @@ int pa__init(pa_module* m) {
speaker = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.Headset',member='SpeakerGainChanged',path='%s'", u->path);
mike = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.Headset',member='MicrophoneGainChanged',path='%s'", u->path);
+ transport = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'");
if (pa_dbus_add_matches(
pa_dbus_connection_get(u->connection), &err,
speaker,
mike,
+ transport,
NULL) < 0) {
pa_xfree(speaker);
pa_xfree(mike);
+ pa_xfree(transport);
pa_log("Failed to add D-Bus matches: %s", err.message);
goto fail;
@@ -2791,6 +2809,7 @@ int pa__init(pa_module* m) {
pa_xfree(speaker);
pa_xfree(mike);
+ pa_xfree(transport);
/* Connect to the BT service */
init_bt(u);
@@ -2855,10 +2874,7 @@ void pa__done(pa_module *m) {
speaker = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.Headset',member='SpeakerGainChanged',path='%s'", u->path);
mike = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.Headset',member='MicrophoneGainChanged',path='%s'", u->path);
- pa_dbus_remove_matches(pa_dbus_connection_get(u->connection),
- speaker,
- mike,
- NULL);
+ pa_dbus_remove_matches(pa_dbus_connection_get(u->connection), speaker, mike, NULL);
pa_xfree(speaker);
pa_xfree(mike);
diff --git a/src/modules/bluetooth/module-bluetooth-proximity.c b/src/modules/bluetooth/module-bluetooth-proximity.c
index 3eed9cea..8c3a5b9f 100644
--- a/src/modules/bluetooth/module-bluetooth-proximity.c
+++ b/src/modules/bluetooth/module-bluetooth-proximity.c
@@ -59,7 +59,6 @@ PA_MODULE_USAGE(
static const char* const valid_modargs[] = {
"sink",
- "rssi",
"hci",
NULL,
};
diff --git a/src/modules/bluetooth/sbc.c b/src/modules/bluetooth/sbc/sbc.c
index 5157c70f..98b236bd 100644
--- a/src/modules/bluetooth/sbc.c
+++ b/src/modules/bluetooth/sbc/sbc.c
@@ -77,7 +77,7 @@ struct sbc_frame {
uint8_t joint;
/* only the lower 4 bits of every element are to be used */
- uint32_t scale_factor[2][8];
+ uint32_t SBC_ALIGNED scale_factor[2][8];
/* raw integer subband samples in the frame */
int32_t SBC_ALIGNED sb_sample_f[16][2][8];
@@ -159,7 +159,8 @@ static uint8_t sbc_crc8(const uint8_t *data, size_t len)
* Takes a pointer to the frame in question, a pointer to the bits array and
* the sampling frequency (as 2 bit integer)
*/
-static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+static SBC_ALWAYS_INLINE void sbc_calculate_bits_internal(
+ const struct sbc_frame *frame, int (*bits)[8], int subbands)
{
uint8_t sf = frame->frequency;
@@ -170,17 +171,17 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
for (ch = 0; ch < frame->channels; ch++) {
max_bitneed = 0;
if (frame->allocation == SNR) {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
bitneed[ch][sb] = frame->scale_factor[ch][sb];
if (bitneed[ch][sb] > max_bitneed)
max_bitneed = bitneed[ch][sb];
}
} else {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if (frame->scale_factor[ch][sb] == 0)
bitneed[ch][sb] = -5;
else {
- if (frame->subbands == 4)
+ if (subbands == 4)
loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
else
loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
@@ -201,7 +202,7 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
bitslice--;
bitcount += slicecount;
slicecount = 0;
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
slicecount++;
else if (bitneed[ch][sb] == bitslice + 1)
@@ -214,7 +215,7 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
bitslice--;
}
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if (bitneed[ch][sb] < bitslice + 2)
bits[ch][sb] = 0;
else {
@@ -224,7 +225,8 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
}
}
- for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+ for (sb = 0; bitcount < frame->bitpool &&
+ sb < subbands; sb++) {
if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
bits[ch][sb]++;
bitcount++;
@@ -234,7 +236,8 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
}
}
- for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+ for (sb = 0; bitcount < frame->bitpool &&
+ sb < subbands; sb++) {
if (bits[ch][sb] < 16) {
bits[ch][sb]++;
bitcount++;
@@ -250,7 +253,7 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
max_bitneed = 0;
if (frame->allocation == SNR) {
for (ch = 0; ch < 2; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
bitneed[ch][sb] = frame->scale_factor[ch][sb];
if (bitneed[ch][sb] > max_bitneed)
max_bitneed = bitneed[ch][sb];
@@ -258,11 +261,11 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
}
} else {
for (ch = 0; ch < 2; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if (frame->scale_factor[ch][sb] == 0)
bitneed[ch][sb] = -5;
else {
- if (frame->subbands == 4)
+ if (subbands == 4)
loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
else
loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
@@ -285,7 +288,7 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
bitcount += slicecount;
slicecount = 0;
for (ch = 0; ch < 2; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
slicecount++;
else if (bitneed[ch][sb] == bitslice + 1)
@@ -300,7 +303,7 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
}
for (ch = 0; ch < 2; ch++) {
- for (sb = 0; sb < frame->subbands; sb++) {
+ for (sb = 0; sb < subbands; sb++) {
if (bitneed[ch][sb] < bitslice + 2) {
bits[ch][sb] = 0;
} else {
@@ -324,7 +327,8 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
if (ch == 1) {
ch = 0;
sb++;
- if (sb >= frame->subbands) break;
+ if (sb >= subbands)
+ break;
} else
ch = 1;
}
@@ -339,7 +343,8 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
if (ch == 1) {
ch = 0;
sb++;
- if (sb >= frame->subbands) break;
+ if (sb >= subbands)
+ break;
} else
ch = 1;
}
@@ -348,6 +353,14 @@ static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
}
+static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+{
+ if (frame->subbands == 4)
+ sbc_calculate_bits_internal(frame, bits, 4);
+ else
+ sbc_calculate_bits_internal(frame, bits, 8);
+}
+
/*
* Unpacks a SBC frame at the beginning of the stream in data,
* which has at most len bytes into frame.
@@ -534,6 +547,16 @@ static void sbc_decoder_init(struct sbc_decoder_state *state,
state->offset[ch][i] = (10 * i + 10);
}
+static SBC_ALWAYS_INLINE int16_t sbc_clip16(int32_t s)
+{
+ if (s > 0x7FFF)
+ return 0x7FFF;
+ else if (s < -0x8000)
+ return -0x8000;
+ else
+ return s;
+}
+
static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
struct sbc_frame *frame, int ch, int blk)
{
@@ -562,7 +585,7 @@ static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
k = (i + 4) & 0xf;
/* Store in output, Q0 */
- frame->pcm_sample[ch][blk * 4 + i] = SCALE4_STAGED1(
+ frame->pcm_sample[ch][blk * 4 + i] = sbc_clip16(SCALE4_STAGED1(
MULA(v[offset[i] + 0], sbc_proto_4_40m0[idx + 0],
MULA(v[offset[k] + 1], sbc_proto_4_40m1[idx + 0],
MULA(v[offset[i] + 2], sbc_proto_4_40m0[idx + 1],
@@ -572,7 +595,7 @@ static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
MULA(v[offset[i] + 6], sbc_proto_4_40m0[idx + 3],
MULA(v[offset[k] + 7], sbc_proto_4_40m1[idx + 3],
MULA(v[offset[i] + 8], sbc_proto_4_40m0[idx + 4],
- MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4])))))))))));
+ MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4]))))))))))));
}
}
@@ -607,8 +630,8 @@ static inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
for (idx = 0, i = 0; i < 8; i++, idx += 5) {
k = (i + 8) & 0xf;
- /* Store in output */
- frame->pcm_sample[ch][blk * 8 + i] = SCALE8_STAGED1( // Q0
+ /* Store in output, Q0 */
+ frame->pcm_sample[ch][blk * 8 + i] = sbc_clip16(SCALE8_STAGED1(
MULA(state->V[ch][offset[i] + 0], sbc_proto_8_80m0[idx + 0],
MULA(state->V[ch][offset[k] + 1], sbc_proto_8_80m1[idx + 0],
MULA(state->V[ch][offset[i] + 2], sbc_proto_8_80m0[idx + 1],
@@ -618,7 +641,7 @@ static inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
MULA(state->V[ch][offset[i] + 6], sbc_proto_8_80m0[idx + 3],
MULA(state->V[ch][offset[k] + 7], sbc_proto_8_80m1[idx + 3],
MULA(state->V[ch][offset[i] + 8], sbc_proto_8_80m0[idx + 4],
- MUL( state->V[ch][offset[k] + 9], sbc_proto_8_80m1[idx + 4])))))))))));
+ MUL( state->V[ch][offset[k] + 9], sbc_proto_8_80m1[idx + 4]))))))))))));
}
}
@@ -732,9 +755,9 @@ static int sbc_analyze_audio(struct sbc_encoder_state *state,
* -99 not implemented
*/
-static SBC_ALWAYS_INLINE int sbc_pack_frame_internal(
+static SBC_ALWAYS_INLINE ssize_t sbc_pack_frame_internal(
uint8_t *data, struct sbc_frame *frame, size_t len,
- int frame_subbands, int frame_channels)
+ int frame_subbands, int frame_channels, int joint)
{
/* Bitstream writer starts from the fourth byte */
uint8_t *data_ptr = data + 4;
@@ -791,63 +814,6 @@ static SBC_ALWAYS_INLINE int sbc_pack_frame_internal(
crc_pos = 16;
if (frame->mode == JOINT_STEREO) {
- /* like frame->sb_sample but joint stereo */
- int32_t sb_sample_j[16][2];
- /* scalefactor and scale_factor in joint case */
- uint32_t scalefactor_j[2];
- uint8_t scale_factor_j[2];
-
- uint8_t joint = 0;
- frame->joint = 0;
-
- for (sb = 0; sb < frame_subbands - 1; sb++) {
- scale_factor_j[0] = 0;
- scalefactor_j[0] = 2 << SCALE_OUT_BITS;
- scale_factor_j[1] = 0;
- scalefactor_j[1] = 2 << SCALE_OUT_BITS;
-
- for (blk = 0; blk < frame->blocks; blk++) {
- uint32_t tmp;
- /* Calculate joint stereo signal */
- sb_sample_j[blk][0] =
- ASR(frame->sb_sample_f[blk][0][sb], 1) +
- ASR(frame->sb_sample_f[blk][1][sb], 1);
- sb_sample_j[blk][1] =
- ASR(frame->sb_sample_f[blk][0][sb], 1) -
- ASR(frame->sb_sample_f[blk][1][sb], 1);
-
- /* calculate scale_factor_j and scalefactor_j for joint case */
- tmp = fabs(sb_sample_j[blk][0]);
- while (scalefactor_j[0] < tmp) {
- scale_factor_j[0]++;
- scalefactor_j[0] *= 2;
- }
- tmp = fabs(sb_sample_j[blk][1]);
- while (scalefactor_j[1] < tmp) {
- scale_factor_j[1]++;
- scalefactor_j[1] *= 2;
- }
- }
-
- /* decide whether to join this subband */
- if ((frame->scale_factor[0][sb] +
- frame->scale_factor[1][sb]) >
- (scale_factor_j[0] +
- scale_factor_j[1])) {
- /* use joint stereo for this subband */
- joint |= 1 << (frame_subbands - 1 - sb);
- frame->joint |= 1 << sb;
- frame->scale_factor[0][sb] = scale_factor_j[0];
- frame->scale_factor[1][sb] = scale_factor_j[1];
- for (blk = 0; blk < frame->blocks; blk++) {
- frame->sb_sample_f[blk][0][sb] =
- sb_sample_j[blk][0];
- frame->sb_sample_f[blk][1][sb] =
- sb_sample_j[blk][1];
- }
- }
- }
-
PUT_BITS(data_ptr, bits_cache, bits_count,
joint, frame_subbands);
crc_header[crc_pos >> 3] = joint;
@@ -905,18 +871,23 @@ static SBC_ALWAYS_INLINE int sbc_pack_frame_internal(
return data_ptr - data;
}
-static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len)
+static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len,
+ int joint)
{
if (frame->subbands == 4) {
if (frame->channels == 1)
- return sbc_pack_frame_internal(data, frame, len, 4, 1);
+ return sbc_pack_frame_internal(
+ data, frame, len, 4, 1, joint);
else
- return sbc_pack_frame_internal(data, frame, len, 4, 2);
+ return sbc_pack_frame_internal(
+ data, frame, len, 4, 2, joint);
} else {
if (frame->channels == 1)
- return sbc_pack_frame_internal(data, frame, len, 8, 1);
+ return sbc_pack_frame_internal(
+ data, frame, len, 8, 1, joint);
else
- return sbc_pack_frame_internal(data, frame, len, 8, 2);
+ return sbc_pack_frame_internal(
+ data, frame, len, 8, 2, joint);
}
}
@@ -924,7 +895,7 @@ static void sbc_encoder_init(struct sbc_encoder_state *state,
const struct sbc_frame *frame)
{
memset(&state->X, 0, sizeof(state->X));
- state->position = SBC_X_BUFFER_SIZE - frame->subbands * 9;
+ state->position = (SBC_X_BUFFER_SIZE - frame->subbands * 9) & ~7;
sbc_init_primitives(state);
}
@@ -1046,10 +1017,11 @@ ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
}
ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
- void *output, size_t output_len, size_t *written)
+ void *output, size_t output_len, ssize_t *written)
{
struct sbc_priv *priv;
- int framelen, samples;
+ int samples;
+ ssize_t framelen;
int (*sbc_enc_process_input)(int position,
const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
int nsamples, int nchannels);
@@ -1114,11 +1086,18 @@ ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
- priv->enc_state.sbc_calc_scalefactors(
- priv->frame.sb_sample_f, priv->frame.scale_factor,
- priv->frame.blocks, priv->frame.channels, priv->frame.subbands);
-
- framelen = sbc_pack_frame(output, &priv->frame, output_len);
+ if (priv->frame.mode == JOINT_STEREO) {
+ int j = priv->enc_state.sbc_calc_scalefactors_j(
+ priv->frame.sb_sample_f, priv->frame.scale_factor,
+ priv->frame.blocks, priv->frame.subbands);
+ framelen = sbc_pack_frame(output, &priv->frame, output_len, j);
+ } else {
+ priv->enc_state.sbc_calc_scalefactors(
+ priv->frame.sb_sample_f, priv->frame.scale_factor,
+ priv->frame.blocks, priv->frame.channels,
+ priv->frame.subbands);
+ framelen = sbc_pack_frame(output, &priv->frame, output_len, 0);
+ }
if (written)
*written = framelen;
@@ -1131,8 +1110,7 @@ void sbc_finish(sbc_t *sbc)
if (!sbc)
return;
- if (sbc->priv_alloc_base)
- free(sbc->priv_alloc_base);
+ free(sbc->priv_alloc_base);
memset(sbc, 0, sizeof(sbc_t));
}
diff --git a/src/modules/bluetooth/sbc.h b/src/modules/bluetooth/sbc/sbc.h
index 65435884..c9c56d38 100644
--- a/src/modules/bluetooth/sbc.h
+++ b/src/modules/bluetooth/sbc/sbc.h
@@ -90,7 +90,7 @@ ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
/* Encodes ONE input block into ONE output block */
ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
- void *output, size_t output_len, size_t *written);
+ void *output, size_t output_len, ssize_t *written);
/* Returns the output block size in bytes */
size_t sbc_get_frame_length(sbc_t *sbc);
diff --git a/src/modules/bluetooth/sbc_math.h b/src/modules/bluetooth/sbc/sbc_math.h
index b87bc81c..b87bc81c 100644
--- a/src/modules/bluetooth/sbc_math.h
+++ b/src/modules/bluetooth/sbc/sbc_math.h
diff --git a/src/modules/bluetooth/sbc_primitives.c b/src/modules/bluetooth/sbc/sbc_primitives.c
index 6b0be3f5..3a76a7a0 100644
--- a/src/modules/bluetooth/sbc_primitives.c
+++ b/src/modules/bluetooth/sbc/sbc_primitives.c
@@ -32,7 +32,9 @@
#include "sbc_primitives.h"
#include "sbc_primitives_mmx.h"
+#include "sbc_primitives_iwmmxt.h"
#include "sbc_primitives_neon.h"
+#include "sbc_primitives_armv6.h"
/*
* A reference C code of analysis filter with SIMD-friendly tables
@@ -231,12 +233,12 @@ static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s4_internal(
/* handle X buffer wraparound */
if (position < nsamples) {
if (nchannels > 0)
- memcpy(&X[0][SBC_X_BUFFER_SIZE - 36], &X[0][position],
+ memcpy(&X[0][SBC_X_BUFFER_SIZE - 40], &X[0][position],
36 * sizeof(int16_t));
if (nchannels > 1)
- memcpy(&X[1][SBC_X_BUFFER_SIZE - 36], &X[1][position],
+ memcpy(&X[1][SBC_X_BUFFER_SIZE - 40], &X[1][position],
36 * sizeof(int16_t));
- position = SBC_X_BUFFER_SIZE - 36;
+ position = SBC_X_BUFFER_SIZE - 40;
}
#define PCM(i) (big_endian ? \
@@ -439,6 +441,80 @@ static void sbc_calc_scalefactors(
}
}
+static int sbc_calc_scalefactors_j(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int subbands)
+{
+ int blk, joint = 0;
+ int32_t tmp0, tmp1;
+ uint32_t x, y;
+
+ /* last subband does not use joint stereo */
+ int sb = subbands - 1;
+ x = 1 << SCALE_OUT_BITS;
+ y = 1 << SCALE_OUT_BITS;
+ for (blk = 0; blk < blocks; blk++) {
+ tmp0 = fabs(sb_sample_f[blk][0][sb]);
+ tmp1 = fabs(sb_sample_f[blk][1][sb]);
+ if (tmp0 != 0)
+ x |= tmp0 - 1;
+ if (tmp1 != 0)
+ y |= tmp1 - 1;
+ }
+ scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(x);
+ scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(y);
+
+ /* the rest of subbands can use joint stereo */
+ while (--sb >= 0) {
+ int32_t sb_sample_j[16][2];
+ x = 1 << SCALE_OUT_BITS;
+ y = 1 << SCALE_OUT_BITS;
+ for (blk = 0; blk < blocks; blk++) {
+ tmp0 = sb_sample_f[blk][0][sb];
+ tmp1 = sb_sample_f[blk][1][sb];
+ sb_sample_j[blk][0] = ASR(tmp0, 1) + ASR(tmp1, 1);
+ sb_sample_j[blk][1] = ASR(tmp0, 1) - ASR(tmp1, 1);
+ tmp0 = fabs(tmp0);
+ tmp1 = fabs(tmp1);
+ if (tmp0 != 0)
+ x |= tmp0 - 1;
+ if (tmp1 != 0)
+ y |= tmp1 - 1;
+ }
+ scale_factor[0][sb] = (31 - SCALE_OUT_BITS) -
+ sbc_clz(x);
+ scale_factor[1][sb] = (31 - SCALE_OUT_BITS) -
+ sbc_clz(y);
+ x = 1 << SCALE_OUT_BITS;
+ y = 1 << SCALE_OUT_BITS;
+ for (blk = 0; blk < blocks; blk++) {
+ tmp0 = fabs(sb_sample_j[blk][0]);
+ tmp1 = fabs(sb_sample_j[blk][1]);
+ if (tmp0 != 0)
+ x |= tmp0 - 1;
+ if (tmp1 != 0)
+ y |= tmp1 - 1;
+ }
+ x = (31 - SCALE_OUT_BITS) - sbc_clz(x);
+ y = (31 - SCALE_OUT_BITS) - sbc_clz(y);
+
+ /* decide whether to use joint stereo for this subband */
+ if ((scale_factor[0][sb] + scale_factor[1][sb]) > x + y) {
+ joint |= 1 << (subbands - 1 - sb);
+ scale_factor[0][sb] = x;
+ scale_factor[1][sb] = y;
+ for (blk = 0; blk < blocks; blk++) {
+ sb_sample_f[blk][0][sb] = sb_sample_j[blk][0];
+ sb_sample_f[blk][1][sb] = sb_sample_j[blk][1];
+ }
+ }
+ }
+
+ /* bitmask with the information about subbands using joint stereo */
+ return joint;
+}
+
/*
* Detect CPU features and setup function pointers
*/
@@ -456,6 +532,7 @@ void sbc_init_primitives(struct sbc_encoder_state *state)
/* Default implementation for scale factors calculation */
state->sbc_calc_scalefactors = sbc_calc_scalefactors;
+ state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j;
state->implementation_info = "Generic C";
/* X86/AMD64 optimizations */
@@ -464,6 +541,12 @@ void sbc_init_primitives(struct sbc_encoder_state *state)
#endif
/* ARM optimizations */
+#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
+ sbc_init_primitives_armv6(state);
+#endif
+#ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT
+ sbc_init_primitives_iwmmxt(state);
+#endif
#ifdef SBC_BUILD_WITH_NEON_SUPPORT
sbc_init_primitives_neon(state);
#endif
diff --git a/src/modules/bluetooth/sbc_primitives.h b/src/modules/bluetooth/sbc/sbc_primitives.h
index 3d01c115..b4b9df2f 100644
--- a/src/modules/bluetooth/sbc_primitives.h
+++ b/src/modules/bluetooth/sbc/sbc_primitives.h
@@ -62,6 +62,10 @@ struct sbc_encoder_state {
void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16][2][8],
uint32_t scale_factor[2][8],
int blocks, int channels, int subbands);
+ /* Scale factors calculation with joint stereo support */
+ int (*sbc_calc_scalefactors_j)(int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int subbands);
const char *implementation_info;
};
diff --git a/src/modules/bluetooth/sbc/sbc_primitives_armv6.c b/src/modules/bluetooth/sbc/sbc_primitives_armv6.c
new file mode 100644
index 00000000..95860980
--- /dev/null
+++ b/src/modules/bluetooth/sbc/sbc_primitives_armv6.c
@@ -0,0 +1,299 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_armv6.h"
+
+/*
+ * ARMv6 optimizations. The instructions are scheduled for ARM11 pipeline.
+ */
+
+#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
+
+static void __attribute__((naked)) sbc_analyze_four_armv6()
+{
+ /* r0 = in, r1 = out, r2 = consts */
+ asm volatile (
+ "push {r1, r4-r7, lr}\n"
+ "push {r8-r11}\n"
+ "ldrd r4, r5, [r0, #0]\n"
+ "ldrd r6, r7, [r2, #0]\n"
+ "ldrd r8, r9, [r0, #16]\n"
+ "ldrd r10, r11, [r2, #16]\n"
+ "mov r14, #0x8000\n"
+ "smlad r3, r4, r6, r14\n"
+ "smlad r12, r5, r7, r14\n"
+ "ldrd r4, r5, [r0, #32]\n"
+ "ldrd r6, r7, [r2, #32]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #48]\n"
+ "ldrd r10, r11, [r2, #48]\n"
+ "smlad r3, r4, r6, r3\n"
+ "smlad r12, r5, r7, r12\n"
+ "ldrd r4, r5, [r0, #64]\n"
+ "ldrd r6, r7, [r2, #64]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #8]\n"
+ "ldrd r10, r11, [r2, #8]\n"
+ "smlad r3, r4, r6, r3\n" /* t1[0] is done */
+ "smlad r12, r5, r7, r12\n" /* t1[1] is done */
+ "ldrd r4, r5, [r0, #24]\n"
+ "ldrd r6, r7, [r2, #24]\n"
+ "pkhtb r3, r12, r3, asr #16\n" /* combine t1[0] and t1[1] */
+ "smlad r12, r8, r10, r14\n"
+ "smlad r14, r9, r11, r14\n"
+ "ldrd r8, r9, [r0, #40]\n"
+ "ldrd r10, r11, [r2, #40]\n"
+ "smlad r12, r4, r6, r12\n"
+ "smlad r14, r5, r7, r14\n"
+ "ldrd r4, r5, [r0, #56]\n"
+ "ldrd r6, r7, [r2, #56]\n"
+ "smlad r12, r8, r10, r12\n"
+ "smlad r14, r9, r11, r14\n"
+ "ldrd r8, r9, [r0, #72]\n"
+ "ldrd r10, r11, [r2, #72]\n"
+ "smlad r12, r4, r6, r12\n"
+ "smlad r14, r5, r7, r14\n"
+ "ldrd r4, r5, [r2, #80]\n" /* start loading cos table */
+ "smlad r12, r8, r10, r12\n" /* t1[2] is done */
+ "smlad r14, r9, r11, r14\n" /* t1[3] is done */
+ "ldrd r6, r7, [r2, #88]\n"
+ "ldrd r8, r9, [r2, #96]\n"
+ "ldrd r10, r11, [r2, #104]\n" /* cos table fully loaded */
+ "pkhtb r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
+ "smuad r4, r3, r4\n"
+ "smuad r5, r3, r5\n"
+ "smlad r4, r12, r8, r4\n"
+ "smlad r5, r12, r9, r5\n"
+ "smuad r6, r3, r6\n"
+ "smuad r7, r3, r7\n"
+ "smlad r6, r12, r10, r6\n"
+ "smlad r7, r12, r11, r7\n"
+ "pop {r8-r11}\n"
+ "stmia r1, {r4, r5, r6, r7}\n"
+ "pop {r1, r4-r7, pc}\n"
+ );
+}
+
+#define sbc_analyze_four(in, out, consts) \
+ ((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
+ sbc_analyze_four_armv6)((in), (out), (consts))
+
+static void __attribute__((naked)) sbc_analyze_eight_armv6()
+{
+ /* r0 = in, r1 = out, r2 = consts */
+ asm volatile (
+ "push {r1, r4-r7, lr}\n"
+ "push {r8-r11}\n"
+ "ldrd r4, r5, [r0, #24]\n"
+ "ldrd r6, r7, [r2, #24]\n"
+ "ldrd r8, r9, [r0, #56]\n"
+ "ldrd r10, r11, [r2, #56]\n"
+ "mov r14, #0x8000\n"
+ "smlad r3, r4, r6, r14\n"
+ "smlad r12, r5, r7, r14\n"
+ "ldrd r4, r5, [r0, #88]\n"
+ "ldrd r6, r7, [r2, #88]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #120]\n"
+ "ldrd r10, r11, [r2, #120]\n"
+ "smlad r3, r4, r6, r3\n"
+ "smlad r12, r5, r7, r12\n"
+ "ldrd r4, r5, [r0, #152]\n"
+ "ldrd r6, r7, [r2, #152]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #16]\n"
+ "ldrd r10, r11, [r2, #16]\n"
+ "smlad r3, r4, r6, r3\n" /* t1[6] is done */
+ "smlad r12, r5, r7, r12\n" /* t1[7] is done */
+ "ldrd r4, r5, [r0, #48]\n"
+ "ldrd r6, r7, [r2, #48]\n"
+ "pkhtb r3, r12, r3, asr #16\n" /* combine t1[6] and t1[7] */
+ "str r3, [sp, #-4]!\n" /* save to stack */
+ "smlad r3, r8, r10, r14\n"
+ "smlad r12, r9, r11, r14\n"
+ "ldrd r8, r9, [r0, #80]\n"
+ "ldrd r10, r11, [r2, #80]\n"
+ "smlad r3, r4, r6, r3\n"
+ "smlad r12, r5, r7, r12\n"
+ "ldrd r4, r5, [r0, #112]\n"
+ "ldrd r6, r7, [r2, #112]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #144]\n"
+ "ldrd r10, r11, [r2, #144]\n"
+ "smlad r3, r4, r6, r3\n"
+ "smlad r12, r5, r7, r12\n"
+ "ldrd r4, r5, [r0, #0]\n"
+ "ldrd r6, r7, [r2, #0]\n"
+ "smlad r3, r8, r10, r3\n" /* t1[4] is done */
+ "smlad r12, r9, r11, r12\n" /* t1[5] is done */
+ "ldrd r8, r9, [r0, #32]\n"
+ "ldrd r10, r11, [r2, #32]\n"
+ "pkhtb r3, r12, r3, asr #16\n" /* combine t1[4] and t1[5] */
+ "str r3, [sp, #-4]!\n" /* save to stack */
+ "smlad r3, r4, r6, r14\n"
+ "smlad r12, r5, r7, r14\n"
+ "ldrd r4, r5, [r0, #64]\n"
+ "ldrd r6, r7, [r2, #64]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #96]\n"
+ "ldrd r10, r11, [r2, #96]\n"
+ "smlad r3, r4, r6, r3\n"
+ "smlad r12, r5, r7, r12\n"
+ "ldrd r4, r5, [r0, #128]\n"
+ "ldrd r6, r7, [r2, #128]\n"
+ "smlad r3, r8, r10, r3\n"
+ "smlad r12, r9, r11, r12\n"
+ "ldrd r8, r9, [r0, #8]\n"
+ "ldrd r10, r11, [r2, #8]\n"
+ "smlad r3, r4, r6, r3\n" /* t1[0] is done */
+ "smlad r12, r5, r7, r12\n" /* t1[1] is done */
+ "ldrd r4, r5, [r0, #40]\n"
+ "ldrd r6, r7, [r2, #40]\n"
+ "pkhtb r3, r12, r3, asr #16\n" /* combine t1[0] and t1[1] */
+ "smlad r12, r8, r10, r14\n"
+ "smlad r14, r9, r11, r14\n"
+ "ldrd r8, r9, [r0, #72]\n"
+ "ldrd r10, r11, [r2, #72]\n"
+ "smlad r12, r4, r6, r12\n"
+ "smlad r14, r5, r7, r14\n"
+ "ldrd r4, r5, [r0, #104]\n"
+ "ldrd r6, r7, [r2, #104]\n"
+ "smlad r12, r8, r10, r12\n"
+ "smlad r14, r9, r11, r14\n"
+ "ldrd r8, r9, [r0, #136]\n"
+ "ldrd r10, r11, [r2, #136]!\n"
+ "smlad r12, r4, r6, r12\n"
+ "smlad r14, r5, r7, r14\n"
+ "ldrd r4, r5, [r2, #(160 - 136 + 0)]\n"
+ "smlad r12, r8, r10, r12\n" /* t1[2] is done */
+ "smlad r14, r9, r11, r14\n" /* t1[3] is done */
+ "ldrd r6, r7, [r2, #(160 - 136 + 8)]\n"
+ "smuad r4, r3, r4\n"
+ "smuad r5, r3, r5\n"
+ "pkhtb r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
+ /* r3 = t2[0:1] */
+ /* r12 = t2[2:3] */
+ "pop {r0, r14}\n" /* t2[4:5], t2[6:7] */
+ "ldrd r8, r9, [r2, #(160 - 136 + 32)]\n"
+ "smuad r6, r3, r6\n"
+ "smuad r7, r3, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 40)]\n"
+ "smlad r4, r12, r8, r4\n"
+ "smlad r5, r12, r9, r5\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 64)]\n"
+ "smlad r6, r12, r10, r6\n"
+ "smlad r7, r12, r11, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 72)]\n"
+ "smlad r4, r0, r8, r4\n"
+ "smlad r5, r0, r9, r5\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 96)]\n"
+ "smlad r6, r0, r10, r6\n"
+ "smlad r7, r0, r11, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 104)]\n"
+ "smlad r4, r14, r8, r4\n"
+ "smlad r5, r14, r9, r5\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 16 + 0)]\n"
+ "smlad r6, r14, r10, r6\n"
+ "smlad r7, r14, r11, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 16 + 8)]\n"
+ "stmia r1!, {r4, r5}\n"
+ "smuad r4, r3, r8\n"
+ "smuad r5, r3, r9\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 16 + 32)]\n"
+ "stmia r1!, {r6, r7}\n"
+ "smuad r6, r3, r10\n"
+ "smuad r7, r3, r11\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 16 + 40)]\n"
+ "smlad r4, r12, r8, r4\n"
+ "smlad r5, r12, r9, r5\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 16 + 64)]\n"
+ "smlad r6, r12, r10, r6\n"
+ "smlad r7, r12, r11, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 16 + 72)]\n"
+ "smlad r4, r0, r8, r4\n"
+ "smlad r5, r0, r9, r5\n"
+ "ldrd r8, r9, [r2, #(160 - 136 + 16 + 96)]\n"
+ "smlad r6, r0, r10, r6\n"
+ "smlad r7, r0, r11, r7\n"
+ "ldrd r10, r11, [r2, #(160 - 136 + 16 + 104)]\n"
+ "smlad r4, r14, r8, r4\n"
+ "smlad r5, r14, r9, r5\n"
+ "smlad r6, r14, r10, r6\n"
+ "smlad r7, r14, r11, r7\n"
+ "pop {r8-r11}\n"
+ "stmia r1!, {r4, r5, r6, r7}\n"
+ "pop {r1, r4-r7, pc}\n"
+ );
+}
+
+#define sbc_analyze_eight(in, out, consts) \
+ ((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
+ sbc_analyze_eight_armv6)((in), (out), (consts))
+
+static void sbc_analyze_4b_4s_armv6(int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_four(x + 12, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four(x + 8, out, analysis_consts_fixed4_simd_even);
+ out += out_stride;
+ sbc_analyze_four(x + 4, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static void sbc_analyze_4b_8s_armv6(int16_t *x, int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_eight(x + 24, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight(x + 16, out, analysis_consts_fixed8_simd_even);
+ out += out_stride;
+ sbc_analyze_eight(x + 8, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+void sbc_init_primitives_armv6(struct sbc_encoder_state *state)
+{
+ state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_armv6;
+ state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_armv6;
+ state->implementation_info = "ARMv6 SIMD";
+}
+
+#endif
diff --git a/src/modules/bluetooth/sbc/sbc_primitives_armv6.h b/src/modules/bluetooth/sbc/sbc_primitives_armv6.h
new file mode 100644
index 00000000..1862aede
--- /dev/null
+++ b/src/modules/bluetooth/sbc/sbc_primitives_armv6.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_ARMV6_H
+#define __SBC_PRIMITIVES_ARMV6_H
+
+#include "sbc_primitives.h"
+
+#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
+ defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
+ defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \
+ defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7__) || \
+ defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \
+ defined(__ARM_ARCH_7M__)
+#define SBC_HAVE_ARMV6 1
+#endif
+
+#if !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) && \
+ defined(__GNUC__) && defined(SBC_HAVE_ARMV6) && \
+ defined(__ARM_EABI__) && !defined(__thumb__) && \
+ !defined(__ARM_NEON__)
+
+#define SBC_BUILD_WITH_ARMV6_SUPPORT
+
+void sbc_init_primitives_armv6(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
diff --git a/src/modules/bluetooth/sbc/sbc_primitives_iwmmxt.c b/src/modules/bluetooth/sbc/sbc_primitives_iwmmxt.c
new file mode 100644
index 00000000..213967ef
--- /dev/null
+++ b/src/modules/bluetooth/sbc/sbc_primitives_iwmmxt.c
@@ -0,0 +1,304 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2010 Keith Mok <ek9852@gmail.com>
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_iwmmxt.h"
+
+/*
+ * IWMMXT optimizations
+ */
+
+#ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT
+
+static inline void sbc_analyze_four_iwmmxt(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ asm volatile (
+ "wldrd wr0, [%0]\n"
+ "tbcstw wr4, %2\n"
+ "wldrd wr2, [%1]\n"
+ "wldrd wr1, [%0, #8]\n"
+ "wldrd wr3, [%1, #8]\n"
+ "wmadds wr0, wr2, wr0\n"
+ " wldrd wr6, [%0, #16]\n"
+ "wmadds wr1, wr3, wr1\n"
+ " wldrd wr7, [%0, #24]\n"
+ "waddwss wr0, wr0, wr4\n"
+ " wldrd wr8, [%1, #16]\n"
+ "waddwss wr1, wr1, wr4\n"
+ " wldrd wr9, [%1, #24]\n"
+ " wmadds wr6, wr8, wr6\n"
+ " wldrd wr2, [%0, #32]\n"
+ " wmadds wr7, wr9, wr7\n"
+ " wldrd wr3, [%0, #40]\n"
+ " waddwss wr0, wr6, wr0\n"
+ " wldrd wr4, [%1, #32]\n"
+ " waddwss wr1, wr7, wr1\n"
+ " wldrd wr5, [%1, #40]\n"
+ " wmadds wr2, wr4, wr2\n"
+ "wldrd wr6, [%0, #48]\n"
+ " wmadds wr3, wr5, wr3\n"
+ "wldrd wr7, [%0, #56]\n"
+ " waddwss wr0, wr2, wr0\n"
+ "wldrd wr8, [%1, #48]\n"
+ " waddwss wr1, wr3, wr1\n"
+ "wldrd wr9, [%1, #56]\n"
+ "wmadds wr6, wr8, wr6\n"
+ " wldrd wr2, [%0, #64]\n"
+ "wmadds wr7, wr9, wr7\n"
+ " wldrd wr3, [%0, #72]\n"
+ "waddwss wr0, wr6, wr0\n"
+ " wldrd wr4, [%1, #64]\n"
+ "waddwss wr1, wr7, wr1\n"
+ " wldrd wr5, [%1, #72]\n"
+ " wmadds wr2, wr4, wr2\n"
+ "tmcr wcgr0, %4\n"
+ " wmadds wr3, wr5, wr3\n"
+ " waddwss wr0, wr2, wr0\n"
+ " waddwss wr1, wr3, wr1\n"
+ "\n"
+ "wsrawg wr0, wr0, wcgr0\n"
+ " wldrd wr4, [%1, #80]\n"
+ "wsrawg wr1, wr1, wcgr0\n"
+ " wldrd wr5, [%1, #88]\n"
+ "wpackwss wr0, wr0, wr0\n"
+ " wldrd wr6, [%1, #96]\n"
+ "wpackwss wr1, wr1, wr1\n"
+ "wmadds wr2, wr5, wr0\n"
+ " wldrd wr7, [%1, #104]\n"
+ "wmadds wr0, wr4, wr0\n"
+ "\n"
+ " wmadds wr3, wr7, wr1\n"
+ " wmadds wr1, wr6, wr1\n"
+ " waddwss wr2, wr3, wr2\n"
+ " waddwss wr0, wr1, wr0\n"
+ "\n"
+ "wstrd wr0, [%3]\n"
+ "wstrd wr2, [%3, #8]\n"
+ :
+ : "r" (in), "r" (consts),
+ "r" (1 << (SBC_PROTO_FIXED4_SCALE - 1)), "r" (out),
+ "r" (SBC_PROTO_FIXED4_SCALE)
+ : "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
+ "wr8", "wr9", "wcgr0", "memory");
+}
+
+static inline void sbc_analyze_eight_iwmmxt(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ asm volatile (
+ "wldrd wr0, [%0]\n"
+ "tbcstw wr15, %2\n"
+ "wldrd wr1, [%0, #8]\n"
+ "wldrd wr2, [%0, #16]\n"
+ "wldrd wr3, [%0, #24]\n"
+ "wldrd wr4, [%1]\n"
+ "wldrd wr5, [%1, #8]\n"
+ "wldrd wr6, [%1, #16]\n"
+ "wldrd wr7, [%1, #24]\n"
+ "wmadds wr0, wr0, wr4\n"
+ " wldrd wr8, [%1, #32]\n"
+ "wmadds wr1, wr1, wr5\n"
+ " wldrd wr9, [%1, #40]\n"
+ "wmadds wr2, wr2, wr6\n"
+ " wldrd wr10, [%1, #48]\n"
+ "wmadds wr3, wr3, wr7\n"
+ " wldrd wr11, [%1, #56]\n"
+ "waddwss wr0, wr0, wr15\n"
+ " wldrd wr4, [%0, #32]\n"
+ "waddwss wr1, wr1, wr15\n"
+ " wldrd wr5, [%0, #40]\n"
+ "waddwss wr2, wr2, wr15\n"
+ " wldrd wr6, [%0, #48]\n"
+ "waddwss wr3, wr3, wr15\n"
+ " wldrd wr7, [%0, #56]\n"
+ " wmadds wr4, wr4, wr8\n"
+ " wldrd wr12, [%0, #64]\n"
+ " wmadds wr5, wr5, wr9\n"
+ " wldrd wr13, [%0, #72]\n"
+ " wmadds wr6, wr6, wr10\n"
+ " wldrd wr14, [%0, #80]\n"
+ " wmadds wr7, wr7, wr11\n"
+ " wldrd wr15, [%0, #88]\n"
+ " waddwss wr0, wr4, wr0\n"
+ " wldrd wr8, [%1, #64]\n"
+ " waddwss wr1, wr5, wr1\n"
+ " wldrd wr9, [%1, #72]\n"
+ " waddwss wr2, wr6, wr2\n"
+ " wldrd wr10, [%1, #80]\n"
+ " waddwss wr3, wr7, wr3\n"
+ " wldrd wr11, [%1, #88]\n"
+ " wmadds wr12, wr12, wr8\n"
+ "wldrd wr4, [%0, #96]\n"
+ " wmadds wr13, wr13, wr9\n"
+ "wldrd wr5, [%0, #104]\n"
+ " wmadds wr14, wr14, wr10\n"
+ "wldrd wr6, [%0, #112]\n"
+ " wmadds wr15, wr15, wr11\n"
+ "wldrd wr7, [%0, #120]\n"
+ " waddwss wr0, wr12, wr0\n"
+ "wldrd wr8, [%1, #96]\n"
+ " waddwss wr1, wr13, wr1\n"
+ "wldrd wr9, [%1, #104]\n"
+ " waddwss wr2, wr14, wr2\n"
+ "wldrd wr10, [%1, #112]\n"
+ " waddwss wr3, wr15, wr3\n"
+ "wldrd wr11, [%1, #120]\n"
+ "wmadds wr4, wr4, wr8\n"
+ " wldrd wr12, [%0, #128]\n"
+ "wmadds wr5, wr5, wr9\n"
+ " wldrd wr13, [%0, #136]\n"
+ "wmadds wr6, wr6, wr10\n"
+ " wldrd wr14, [%0, #144]\n"
+ "wmadds wr7, wr7, wr11\n"
+ " wldrd wr15, [%0, #152]\n"
+ "waddwss wr0, wr4, wr0\n"
+ " wldrd wr8, [%1, #128]\n"
+ "waddwss wr1, wr5, wr1\n"
+ " wldrd wr9, [%1, #136]\n"
+ "waddwss wr2, wr6, wr2\n"
+ " wldrd wr10, [%1, #144]\n"
+ " waddwss wr3, wr7, wr3\n"
+ " wldrd wr11, [%1, #152]\n"
+ " wmadds wr12, wr12, wr8\n"
+ "tmcr wcgr0, %4\n"
+ " wmadds wr13, wr13, wr9\n"
+ " wmadds wr14, wr14, wr10\n"
+ " wmadds wr15, wr15, wr11\n"
+ " waddwss wr0, wr12, wr0\n"
+ " waddwss wr1, wr13, wr1\n"
+ " waddwss wr2, wr14, wr2\n"
+ " waddwss wr3, wr15, wr3\n"
+ "\n"
+ "wsrawg wr0, wr0, wcgr0\n"
+ "wsrawg wr1, wr1, wcgr0\n"
+ "wsrawg wr2, wr2, wcgr0\n"
+ "wsrawg wr3, wr3, wcgr0\n"
+ "\n"
+ "wpackwss wr0, wr0, wr0\n"
+ "wpackwss wr1, wr1, wr1\n"
+ " wldrd wr4, [%1, #160]\n"
+ "wpackwss wr2, wr2, wr2\n"
+ " wldrd wr5, [%1, #168]\n"
+ "wpackwss wr3, wr3, wr3\n"
+ " wldrd wr6, [%1, #192]\n"
+ " wmadds wr4, wr4, wr0\n"
+ " wldrd wr7, [%1, #200]\n"
+ " wmadds wr5, wr5, wr0\n"
+ " wldrd wr8, [%1, #224]\n"
+ " wmadds wr6, wr6, wr1\n"
+ " wldrd wr9, [%1, #232]\n"
+ " wmadds wr7, wr7, wr1\n"
+ " waddwss wr4, wr6, wr4\n"
+ " waddwss wr5, wr7, wr5\n"
+ " wmadds wr8, wr8, wr2\n"
+ "wldrd wr6, [%1, #256]\n"
+ " wmadds wr9, wr9, wr2\n"
+ "wldrd wr7, [%1, #264]\n"
+ "waddwss wr4, wr8, wr4\n"
+ " waddwss wr5, wr9, wr5\n"
+ "wmadds wr6, wr6, wr3\n"
+ "wmadds wr7, wr7, wr3\n"
+ "waddwss wr4, wr6, wr4\n"
+ "waddwss wr5, wr7, wr5\n"
+ "\n"
+ "wstrd wr4, [%3]\n"
+ "wstrd wr5, [%3, #8]\n"
+ "\n"
+ "wldrd wr6, [%1, #176]\n"
+ "wldrd wr5, [%1, #184]\n"
+ "wmadds wr5, wr5, wr0\n"
+ "wldrd wr8, [%1, #208]\n"
+ "wmadds wr0, wr6, wr0\n"
+ "wldrd wr9, [%1, #216]\n"
+ "wmadds wr9, wr9, wr1\n"
+ "wldrd wr6, [%1, #240]\n"
+ "wmadds wr1, wr8, wr1\n"
+ "wldrd wr7, [%1, #248]\n"
+ "waddwss wr0, wr1, wr0\n"
+ "waddwss wr5, wr9, wr5\n"
+ "wmadds wr7, wr7, wr2\n"
+ "wldrd wr8, [%1, #272]\n"
+ "wmadds wr2, wr6, wr2\n"
+ "wldrd wr9, [%1, #280]\n"
+ "waddwss wr0, wr2, wr0\n"
+ "waddwss wr5, wr7, wr5\n"
+ "wmadds wr9, wr9, wr3\n"
+ "wmadds wr3, wr8, wr3\n"
+ "waddwss wr0, wr3, wr0\n"
+ "waddwss wr5, wr9, wr5\n"
+ "\n"
+ "wstrd wr0, [%3, #16]\n"
+ "wstrd wr5, [%3, #24]\n"
+ :
+ : "r" (in), "r" (consts),
+ "r" (1 << (SBC_PROTO_FIXED8_SCALE - 1)), "r" (out),
+ "r" (SBC_PROTO_FIXED8_SCALE)
+ : "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
+ "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15",
+ "wcgr0", "memory");
+}
+
+static inline void sbc_analyze_4b_4s_iwmmxt(int16_t *x, int32_t *out,
+ int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_four_iwmmxt(x + 12, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four_iwmmxt(x + 8, out, analysis_consts_fixed4_simd_even);
+ out += out_stride;
+ sbc_analyze_four_iwmmxt(x + 4, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ sbc_analyze_four_iwmmxt(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static inline void sbc_analyze_4b_8s_iwmmxt(int16_t *x, int32_t *out,
+ int out_stride)
+{
+ /* Analyze blocks */
+ sbc_analyze_eight_iwmmxt(x + 24, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight_iwmmxt(x + 16, out, analysis_consts_fixed8_simd_even);
+ out += out_stride;
+ sbc_analyze_eight_iwmmxt(x + 8, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ sbc_analyze_eight_iwmmxt(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *state)
+{
+ state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_iwmmxt;
+ state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_iwmmxt;
+ state->implementation_info = "IWMMXT";
+}
+
+#endif
diff --git a/src/modules/bluetooth/sbc/sbc_primitives_iwmmxt.h b/src/modules/bluetooth/sbc/sbc_primitives_iwmmxt.h
new file mode 100644
index 00000000..b535e686
--- /dev/null
+++ b/src/modules/bluetooth/sbc/sbc_primitives_iwmmxt.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2010 Keith Mok <ek9852@gmail.com>
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_IWMMXT_H
+#define __SBC_PRIMITIVES_IWMMXT_H
+
+#include "sbc_primitives.h"
+
+#if defined(__GNUC__) && defined(__IWMMXT__) && \
+ !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15)
+
+#define SBC_BUILD_WITH_IWMMXT_SUPPORT
+
+void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
diff --git a/src/modules/bluetooth/sbc_primitives_mmx.c b/src/modules/bluetooth/sbc/sbc_primitives_mmx.c
index 08e9ca28..ab89d074 100644
--- a/src/modules/bluetooth/sbc_primitives_mmx.c
+++ b/src/modules/bluetooth/sbc/sbc_primitives_mmx.c
@@ -100,7 +100,7 @@ static inline void sbc_analyze_four_mmx(const int16_t *in, int32_t *out,
:
: "r" (in), "r" (consts), "r" (&round_c), "r" (out),
"i" (SBC_PROTO_FIXED4_SCALE)
- : "memory");
+ : "cc", "memory");
}
static inline void sbc_analyze_eight_mmx(const int16_t *in, int32_t *out,
@@ -242,7 +242,7 @@ static inline void sbc_analyze_eight_mmx(const int16_t *in, int32_t *out,
:
: "r" (in), "r" (consts), "r" (&round_c), "r" (out),
"i" (SBC_PROTO_FIXED8_SCALE)
- : "memory");
+ : "cc", "memory");
}
static inline void sbc_analyze_4b_4s_mmx(int16_t *x, int32_t *out,
@@ -275,6 +275,59 @@ static inline void sbc_analyze_4b_8s_mmx(int16_t *x, int32_t *out,
asm volatile ("emms\n");
}
+static void sbc_calc_scalefactors_mmx(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int channels, int subbands)
+{
+ static const SBC_ALIGNED int32_t consts[2] = {
+ 1 << SCALE_OUT_BITS,
+ 1 << SCALE_OUT_BITS,
+ };
+ int ch, sb;
+ intptr_t blk;
+ for (ch = 0; ch < channels; ch++) {
+ for (sb = 0; sb < subbands; sb += 2) {
+ blk = (blocks - 1) * (((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]));
+ asm volatile (
+ "movq (%4), %%mm0\n"
+ "1:\n"
+ "movq (%1, %0), %%mm1\n"
+ "pxor %%mm2, %%mm2\n"
+ "pcmpgtd %%mm2, %%mm1\n"
+ "paddd (%1, %0), %%mm1\n"
+ "pcmpgtd %%mm1, %%mm2\n"
+ "pxor %%mm2, %%mm1\n"
+
+ "por %%mm1, %%mm0\n"
+
+ "sub %2, %0\n"
+ "jns 1b\n"
+
+ "movd %%mm0, %k0\n"
+ "psrlq $32, %%mm0\n"
+ "bsrl %k0, %k0\n"
+ "subl %5, %k0\n"
+ "movl %k0, (%3)\n"
+
+ "movd %%mm0, %k0\n"
+ "bsrl %k0, %k0\n"
+ "subl %5, %k0\n"
+ "movl %k0, 4(%3)\n"
+ : "+r" (blk)
+ : "r" (&sb_sample_f[0][ch][sb]),
+ "i" ((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]),
+ "r" (&scale_factor[ch][sb]),
+ "r" (&consts),
+ "i" (SCALE_OUT_BITS)
+ : "cc", "memory");
+ }
+ }
+ asm volatile ("emms\n");
+}
+
static int check_mmx_support(void)
{
#ifdef __amd64__
@@ -313,6 +366,7 @@ void sbc_init_primitives_mmx(struct sbc_encoder_state *state)
if (check_mmx_support()) {
state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_mmx;
state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_mmx;
+ state->sbc_calc_scalefactors = sbc_calc_scalefactors_mmx;
state->implementation_info = "MMX";
}
}
diff --git a/src/modules/bluetooth/sbc_primitives_mmx.h b/src/modules/bluetooth/sbc/sbc_primitives_mmx.h
index c1e44a5d..c1e44a5d 100644
--- a/src/modules/bluetooth/sbc_primitives_mmx.h
+++ b/src/modules/bluetooth/sbc/sbc_primitives_mmx.h
diff --git a/src/modules/bluetooth/sbc/sbc_primitives_neon.c b/src/modules/bluetooth/sbc/sbc_primitives_neon.c
new file mode 100644
index 00000000..c233d3c6
--- /dev/null
+++ b/src/modules/bluetooth/sbc/sbc_primitives_neon.c
@@ -0,0 +1,892 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_neon.h"
+
+/*
+ * ARM NEON optimizations
+ */
+
+#ifdef SBC_BUILD_WITH_NEON_SUPPORT
+
+static inline void _sbc_analyze_four_neon(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ /* TODO: merge even and odd cases (or even merge all four calls to this
+ * function) in order to have only aligned reads from 'in' array
+ * and reduce number of load instructions */
+ asm volatile (
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmull.s16 q0, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmull.s16 q1, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+
+ "vmlal.s16 q0, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmlal.s16 q1, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q0, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmlal.s16 q1, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+
+ "vmlal.s16 q0, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmlal.s16 q1, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q0, d4, d8\n"
+ "vmlal.s16 q1, d5, d9\n"
+
+ "vpadd.s32 d0, d0, d1\n"
+ "vpadd.s32 d1, d2, d3\n"
+
+ "vrshrn.s32 d0, q0, %3\n"
+
+ "vld1.16 {d2, d3, d4, d5}, [%1, :128]!\n"
+
+ "vdup.i32 d1, d0[1]\n" /* TODO: can be eliminated */
+ "vdup.i32 d0, d0[0]\n" /* TODO: can be eliminated */
+
+ "vmull.s16 q3, d2, d0\n"
+ "vmull.s16 q4, d3, d0\n"
+ "vmlal.s16 q3, d4, d1\n"
+ "vmlal.s16 q4, d5, d1\n"
+
+ "vpadd.s32 d0, d6, d7\n" /* TODO: can be eliminated */
+ "vpadd.s32 d1, d8, d9\n" /* TODO: can be eliminated */
+
+ "vst1.32 {d0, d1}, [%2, :128]\n"
+ : "+r" (in), "+r" (consts)
+ : "r" (out),
+ "i" (SBC_PROTO_FIXED4_SCALE)
+ : "memory",
+ "d0", "d1", "d2", "d3", "d4", "d5",
+ "d6", "d7", "d8", "d9", "d10", "d11");
+}
+
+static inline void _sbc_analyze_eight_neon(const int16_t *in, int32_t *out,
+ const FIXED_T *consts)
+{
+ /* TODO: merge even and odd cases (or even merge all four calls to this
+ * function) in order to have only aligned reads from 'in' array
+ * and reduce number of load instructions */
+ asm volatile (
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmull.s16 q6, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmull.s16 q7, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+ "vmull.s16 q8, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmull.s16 q9, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q6, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmlal.s16 q7, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+ "vmlal.s16 q8, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmlal.s16 q9, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q6, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmlal.s16 q7, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+ "vmlal.s16 q8, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmlal.s16 q9, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q6, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmlal.s16 q7, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+ "vmlal.s16 q8, d6, d10\n"
+ "vld1.16 {d4, d5}, [%0, :64]!\n"
+ "vmlal.s16 q9, d7, d11\n"
+ "vld1.16 {d8, d9}, [%1, :128]!\n"
+
+ "vmlal.s16 q6, d4, d8\n"
+ "vld1.16 {d6, d7}, [%0, :64]!\n"
+ "vmlal.s16 q7, d5, d9\n"
+ "vld1.16 {d10, d11}, [%1, :128]!\n"
+
+ "vmlal.s16 q8, d6, d10\n"
+ "vmlal.s16 q9, d7, d11\n"
+
+ "vpadd.s32 d0, d12, d13\n"
+ "vpadd.s32 d1, d14, d15\n"
+ "vpadd.s32 d2, d16, d17\n"
+ "vpadd.s32 d3, d18, d19\n"
+
+ "vrshr.s32 q0, q0, %3\n"
+ "vrshr.s32 q1, q1, %3\n"
+ "vmovn.s32 d0, q0\n"
+ "vmovn.s32 d1, q1\n"
+
+ "vdup.i32 d3, d1[1]\n" /* TODO: can be eliminated */
+ "vdup.i32 d2, d1[0]\n" /* TODO: can be eliminated */
+ "vdup.i32 d1, d0[1]\n" /* TODO: can be eliminated */
+ "vdup.i32 d0, d0[0]\n" /* TODO: can be eliminated */
+
+ "vld1.16 {d4, d5}, [%1, :128]!\n"
+ "vmull.s16 q6, d4, d0\n"
+ "vld1.16 {d6, d7}, [%1, :128]!\n"
+ "vmull.s16 q7, d5, d0\n"
+ "vmull.s16 q8, d6, d0\n"
+ "vmull.s16 q9, d7, d0\n"
+
+ "vld1.16 {d4, d5}, [%1, :128]!\n"
+ "vmlal.s16 q6, d4, d1\n"
+ "vld1.16 {d6, d7}, [%1, :128]!\n"
+ "vmlal.s16 q7, d5, d1\n"
+ "vmlal.s16 q8, d6, d1\n"
+ "vmlal.s16 q9, d7, d1\n"
+
+ "vld1.16 {d4, d5}, [%1, :128]!\n"
+ "vmlal.s16 q6, d4, d2\n"
+ "vld1.16 {d6, d7}, [%1, :128]!\n"
+ "vmlal.s16 q7, d5, d2\n"
+ "vmlal.s16 q8, d6, d2\n"
+ "vmlal.s16 q9, d7, d2\n"
+
+ "vld1.16 {d4, d5}, [%1, :128]!\n"
+ "vmlal.s16 q6, d4, d3\n"
+ "vld1.16 {d6, d7}, [%1, :128]!\n"
+ "vmlal.s16 q7, d5, d3\n"
+ "vmlal.s16 q8, d6, d3\n"
+ "vmlal.s16 q9, d7, d3\n"
+
+ "vpadd.s32 d0, d12, d13\n" /* TODO: can be eliminated */
+ "vpadd.s32 d1, d14, d15\n" /* TODO: can be eliminated */
+ "vpadd.s32 d2, d16, d17\n" /* TODO: can be eliminated */
+ "vpadd.s32 d3, d18, d19\n" /* TODO: can be eliminated */
+
+ "vst1.32 {d0, d1, d2, d3}, [%2, :128]\n"
+ : "+r" (in), "+r" (consts)
+ : "r" (out),
+ "i" (SBC_PROTO_FIXED8_SCALE)
+ : "memory",
+ "d0", "d1", "d2", "d3", "d4", "d5",
+ "d6", "d7", "d8", "d9", "d10", "d11",
+ "d12", "d13", "d14", "d15", "d16", "d17",
+ "d18", "d19");
+}
+
+static inline void sbc_analyze_4b_4s_neon(int16_t *x,
+ int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ _sbc_analyze_four_neon(x + 12, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ _sbc_analyze_four_neon(x + 8, out, analysis_consts_fixed4_simd_even);
+ out += out_stride;
+ _sbc_analyze_four_neon(x + 4, out, analysis_consts_fixed4_simd_odd);
+ out += out_stride;
+ _sbc_analyze_four_neon(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static inline void sbc_analyze_4b_8s_neon(int16_t *x,
+ int32_t *out, int out_stride)
+{
+ /* Analyze blocks */
+ _sbc_analyze_eight_neon(x + 24, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ _sbc_analyze_eight_neon(x + 16, out, analysis_consts_fixed8_simd_even);
+ out += out_stride;
+ _sbc_analyze_eight_neon(x + 8, out, analysis_consts_fixed8_simd_odd);
+ out += out_stride;
+ _sbc_analyze_eight_neon(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+static void sbc_calc_scalefactors_neon(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int channels, int subbands)
+{
+ int ch, sb;
+ for (ch = 0; ch < channels; ch++) {
+ for (sb = 0; sb < subbands; sb += 4) {
+ int blk = blocks;
+ int32_t *in = &sb_sample_f[0][ch][sb];
+ asm volatile (
+ "vmov.s32 q0, #0\n"
+ "vmov.s32 q1, %[c1]\n"
+ "vmov.s32 q14, #1\n"
+ "vmov.s32 q15, %[c2]\n"
+ "vadd.s32 q1, q1, q14\n"
+ "1:\n"
+ "vld1.32 {d16, d17}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q8, q8\n"
+ "vld1.32 {d18, d19}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q9, q9\n"
+ "vld1.32 {d20, d21}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q10, q10\n"
+ "vld1.32 {d22, d23}, [%[in], :128], %[inc]\n"
+ "vabs.s32 q11, q11\n"
+ "vmax.s32 q0, q0, q8\n"
+ "vmax.s32 q1, q1, q9\n"
+ "vmax.s32 q0, q0, q10\n"
+ "vmax.s32 q1, q1, q11\n"
+ "subs %[blk], %[blk], #4\n"
+ "bgt 1b\n"
+ "vmax.s32 q0, q0, q1\n"
+ "vsub.s32 q0, q0, q14\n"
+ "vclz.s32 q0, q0\n"
+ "vsub.s32 q0, q15, q0\n"
+ "vst1.32 {d0, d1}, [%[out], :128]\n"
+ :
+ [blk] "+r" (blk),
+ [in] "+r" (in)
+ :
+ [inc] "r" ((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]),
+ [out] "r" (&scale_factor[ch][sb]),
+ [c1] "i" (1 << SCALE_OUT_BITS),
+ [c2] "i" (31 - SCALE_OUT_BITS)
+ : "d0", "d1", "d2", "d3", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23", "d24", "d25", "d26",
+ "d27", "d28", "d29", "d30", "d31", "cc", "memory");
+ }
+ }
+}
+
+int sbc_calc_scalefactors_j_neon(
+ int32_t sb_sample_f[16][2][8],
+ uint32_t scale_factor[2][8],
+ int blocks, int subbands)
+{
+ static SBC_ALIGNED int32_t joint_bits_mask[8] = {
+ 8, 4, 2, 1, 128, 64, 32, 16
+ };
+ int joint, i;
+ int32_t *in0, *in1;
+ int32_t *in = &sb_sample_f[0][0][0];
+ uint32_t *out0, *out1;
+ uint32_t *out = &scale_factor[0][0];
+ int32_t *consts = joint_bits_mask;
+
+ i = subbands;
+
+ asm volatile (
+ /*
+ * constants: q13 = (31 - SCALE_OUT_BITS), q14 = 1
+ * input: q0 = ((1 << SCALE_OUT_BITS) + 1)
+ * %[in0] - samples for channel 0
+ * %[in1] - samples for shannel 1
+ * output: q0, q1 - scale factors without joint stereo
+ * q2, q3 - scale factors with joint stereo
+ * q15 - joint stereo selection mask
+ */
+ ".macro calc_scalefactors\n"
+ "vmov.s32 q1, q0\n"
+ "vmov.s32 q2, q0\n"
+ "vmov.s32 q3, q0\n"
+ "mov %[i], %[blocks]\n"
+ "1:\n"
+ "vld1.32 {d18, d19}, [%[in1], :128], %[inc]\n"
+ "vbic.s32 q11, q9, q14\n"
+ "vld1.32 {d16, d17}, [%[in0], :128], %[inc]\n"
+ "vhadd.s32 q10, q8, q11\n"
+ "vhsub.s32 q11, q8, q11\n"
+ "vabs.s32 q8, q8\n"
+ "vabs.s32 q9, q9\n"
+ "vabs.s32 q10, q10\n"
+ "vabs.s32 q11, q11\n"
+ "vmax.s32 q0, q0, q8\n"
+ "vmax.s32 q1, q1, q9\n"
+ "vmax.s32 q2, q2, q10\n"
+ "vmax.s32 q3, q3, q11\n"
+ "subs %[i], %[i], #1\n"
+ "bgt 1b\n"
+ "vsub.s32 q0, q0, q14\n"
+ "vsub.s32 q1, q1, q14\n"
+ "vsub.s32 q2, q2, q14\n"
+ "vsub.s32 q3, q3, q14\n"
+ "vclz.s32 q0, q0\n"
+ "vclz.s32 q1, q1\n"
+ "vclz.s32 q2, q2\n"
+ "vclz.s32 q3, q3\n"
+ "vsub.s32 q0, q13, q0\n"
+ "vsub.s32 q1, q13, q1\n"
+ "vsub.s32 q2, q13, q2\n"
+ "vsub.s32 q3, q13, q3\n"
+ ".endm\n"
+ /*
+ * constants: q14 = 1
+ * input: q15 - joint stereo selection mask
+ * %[in0] - value set by calc_scalefactors macro
+ * %[in1] - value set by calc_scalefactors macro
+ */
+ ".macro update_joint_stereo_samples\n"
+ "sub %[out1], %[in1], %[inc]\n"
+ "sub %[out0], %[in0], %[inc]\n"
+ "sub %[in1], %[in1], %[inc], asl #1\n"
+ "sub %[in0], %[in0], %[inc], asl #1\n"
+ "vld1.32 {d18, d19}, [%[in1], :128]\n"
+ "vbic.s32 q11, q9, q14\n"
+ "vld1.32 {d16, d17}, [%[in0], :128]\n"
+ "vld1.32 {d2, d3}, [%[out1], :128]\n"
+ "vbic.s32 q3, q1, q14\n"
+ "vld1.32 {d0, d1}, [%[out0], :128]\n"
+ "vhsub.s32 q10, q8, q11\n"
+ "vhadd.s32 q11, q8, q11\n"
+ "vhsub.s32 q2, q0, q3\n"
+ "vhadd.s32 q3, q0, q3\n"
+ "vbif.s32 q10, q9, q15\n"
+ "vbif.s32 d22, d16, d30\n"
+ "sub %[inc], %[zero], %[inc], asl #1\n"
+ "sub %[i], %[blocks], #2\n"
+ "2:\n"
+ "vbif.s32 d23, d17, d31\n"
+ "vst1.32 {d20, d21}, [%[in1], :128], %[inc]\n"
+ "vbif.s32 d4, d2, d30\n"
+ "vld1.32 {d18, d19}, [%[in1], :128]\n"
+ "vbif.s32 d5, d3, d31\n"
+ "vst1.32 {d22, d23}, [%[in0], :128], %[inc]\n"
+ "vbif.s32 d6, d0, d30\n"
+ "vld1.32 {d16, d17}, [%[in0], :128]\n"
+ "vbif.s32 d7, d1, d31\n"
+ "vst1.32 {d4, d5}, [%[out1], :128], %[inc]\n"
+ "vbic.s32 q11, q9, q14\n"
+ "vld1.32 {d2, d3}, [%[out1], :128]\n"
+ "vst1.32 {d6, d7}, [%[out0], :128], %[inc]\n"
+ "vbic.s32 q3, q1, q14\n"
+ "vld1.32 {d0, d1}, [%[out0], :128]\n"
+ "vhsub.s32 q10, q8, q11\n"
+ "vhadd.s32 q11, q8, q11\n"
+ "vhsub.s32 q2, q0, q3\n"
+ "vhadd.s32 q3, q0, q3\n"
+ "vbif.s32 q10, q9, q15\n"
+ "vbif.s32 d22, d16, d30\n"
+ "subs %[i], %[i], #2\n"
+ "bgt 2b\n"
+ "sub %[inc], %[zero], %[inc], asr #1\n"
+ "vbif.s32 d23, d17, d31\n"
+ "vst1.32 {d20, d21}, [%[in1], :128]\n"
+ "vbif.s32 q2, q1, q15\n"
+ "vst1.32 {d22, d23}, [%[in0], :128]\n"
+ "vbif.s32 q3, q0, q15\n"
+ "vst1.32 {d4, d5}, [%[out1], :128]\n"
+ "vst1.32 {d6, d7}, [%[out0], :128]\n"
+ ".endm\n"
+
+ "vmov.s32 q14, #1\n"
+ "vmov.s32 q13, %[c2]\n"
+
+ "cmp %[i], #4\n"
+ "bne 8f\n"
+
+ "4:\n" /* 4 subbands */
+ "add %[in0], %[in], #0\n"
+ "add %[in1], %[in], #32\n"
+ "add %[out0], %[out], #0\n"
+ "add %[out1], %[out], #32\n"
+ "vmov.s32 q0, %[c1]\n"
+ "vadd.s32 q0, q0, q14\n"
+
+ "calc_scalefactors\n"
+
+ /* check whether to use joint stereo for subbands 0, 1, 2 */
+ "vadd.s32 q15, q0, q1\n"
+ "vadd.s32 q9, q2, q3\n"
+ "vmov.s32 d31[1], %[zero]\n" /* last subband -> no joint */
+ "vld1.32 {d16, d17}, [%[consts], :128]!\n"
+ "vcgt.s32 q15, q15, q9\n"
+
+ /* calculate and save to memory 'joint' variable */
+ /* update and save scale factors to memory */
+ " vand.s32 q8, q8, q15\n"
+ "vbit.s32 q0, q2, q15\n"
+ " vpadd.s32 d16, d16, d17\n"
+ "vbit.s32 q1, q3, q15\n"
+ " vpadd.s32 d16, d16, d16\n"
+ "vst1.32 {d0, d1}, [%[out0], :128]\n"
+ "vst1.32 {d2, d3}, [%[out1], :128]\n"
+ " vst1.32 {d16[0]}, [%[joint]]\n"
+
+ "update_joint_stereo_samples\n"
+ "b 9f\n"
+
+ "8:\n" /* 8 subbands */
+ "add %[in0], %[in], #16\n\n"
+ "add %[in1], %[in], #48\n"
+ "add %[out0], %[out], #16\n\n"
+ "add %[out1], %[out], #48\n"
+ "vmov.s32 q0, %[c1]\n"
+ "vadd.s32 q0, q0, q14\n"
+
+ "calc_scalefactors\n"
+
+ /* check whether to use joint stereo for subbands 4, 5, 6 */
+ "vadd.s32 q15, q0, q1\n"
+ "vadd.s32 q9, q2, q3\n"
+ "vmov.s32 d31[1], %[zero]\n" /* last subband -> no joint */
+ "vld1.32 {d16, d17}, [%[consts], :128]!\n"
+ "vcgt.s32 q15, q15, q9\n"
+
+ /* calculate part of 'joint' variable and save it to d24 */
+ /* update and save scale factors to memory */
+ " vand.s32 q8, q8, q15\n"
+ "vbit.s32 q0, q2, q15\n"
+ " vpadd.s32 d16, d16, d17\n"
+ "vbit.s32 q1, q3, q15\n"
+ "vst1.32 {d0, d1}, [%[out0], :128]\n"
+ "vst1.32 {d2, d3}, [%[out1], :128]\n"
+ " vpadd.s32 d24, d16, d16\n"
+
+ "update_joint_stereo_samples\n"
+
+ "add %[in0], %[in], #0\n"
+ "add %[in1], %[in], #32\n"
+ "add %[out0], %[out], #0\n\n"
+ "add %[out1], %[out], #32\n"
+ "vmov.s32 q0, %[c1]\n"
+ "vadd.s32 q0, q0, q14\n"
+
+ "calc_scalefactors\n"
+
+ /* check whether to use joint stereo for subbands 0, 1, 2, 3 */
+ "vadd.s32 q15, q0, q1\n"
+ "vadd.s32 q9, q2, q3\n"
+ "vld1.32 {d16, d17}, [%[consts], :128]!\n"
+ "vcgt.s32 q15, q15, q9\n"
+
+ /* combine last part of 'joint' with d24 and save to memory */
+ /* update and save scale factors to memory */
+ " vand.s32 q8, q8, q15\n"
+ "vbit.s32 q0, q2, q15\n"
+ " vpadd.s32 d16, d16, d17\n"
+ "vbit.s32 q1, q3, q15\n"
+ " vpadd.s32 d16, d16, d16\n"
+ "vst1.32 {d0, d1}, [%[out0], :128]\n"
+ " vadd.s32 d16, d16, d24\n"
+ "vst1.32 {d2, d3}, [%[out1], :128]\n"
+ " vst1.32 {d16[0]}, [%[joint]]\n"
+
+ "update_joint_stereo_samples\n"
+ "9:\n"
+ ".purgem calc_scalefactors\n"
+ ".purgem update_joint_stereo_samples\n"
+ :
+ [i] "+&r" (i),
+ [in] "+&r" (in),
+ [in0] "=&r" (in0),
+ [in1] "=&r" (in1),
+ [out] "+&r" (out),
+ [out0] "=&r" (out0),
+ [out1] "=&r" (out1),
+ [consts] "+&r" (consts)
+ :
+ [inc] "r" ((char *) &sb_sample_f[1][0][0] -
+ (char *) &sb_sample_f[0][0][0]),
+ [blocks] "r" (blocks),
+ [joint] "r" (&joint),
+ [c1] "i" (1 << SCALE_OUT_BITS),
+ [c2] "i" (31 - SCALE_OUT_BITS),
+ [zero] "r" (0)
+ : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+ "d16", "d17", "d18", "d19", "d20", "d21", "d22",
+ "d23", "d24", "d25", "d26", "d27", "d28", "d29",
+ "d30", "d31", "cc", "memory");
+
+ return joint;
+}
+
+#define PERM_BE(a, b, c, d) { \
+ (a * 2) + 1, (a * 2) + 0, \
+ (b * 2) + 1, (b * 2) + 0, \
+ (c * 2) + 1, (c * 2) + 0, \
+ (d * 2) + 1, (d * 2) + 0 \
+ }
+#define PERM_LE(a, b, c, d) { \
+ (a * 2) + 0, (a * 2) + 1, \
+ (b * 2) + 0, (b * 2) + 1, \
+ (c * 2) + 0, (c * 2) + 1, \
+ (d * 2) + 0, (d * 2) + 1 \
+ }
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
+ int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels, int big_endian)
+{
+ static SBC_ALIGNED uint8_t perm_be[2][8] = {
+ PERM_BE(7, 3, 6, 4),
+ PERM_BE(0, 2, 1, 5)
+ };
+ static SBC_ALIGNED uint8_t perm_le[2][8] = {
+ PERM_LE(7, 3, 6, 4),
+ PERM_LE(0, 2, 1, 5)
+ };
+ /* handle X buffer wraparound */
+ if (position < nsamples) {
+ int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 40];
+ int16_t *src = &X[0][position];
+ asm volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0}, [%[src], :64]!\n"
+ "vst1.16 {d0}, [%[dst], :64]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ if (nchannels > 1) {
+ dst = &X[1][SBC_X_BUFFER_SIZE - 40];
+ src = &X[1][position];
+ asm volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0}, [%[src], :64]!\n"
+ "vst1.16 {d0}, [%[dst], :64]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ }
+ position = SBC_X_BUFFER_SIZE - 40;
+ }
+
+ if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+ /* poor 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ asm volatile (
+ "vld1.8 {d0, d1}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #16\n"
+ "sub %[y], %[y], #16\n"
+ "sub %[position], %[position], #8\n"
+ "vld1.8 {d4, d5}, [%[pcm]]!\n"
+ "vuzp.16 d4, d5\n"
+ "vld1.8 {d20, d21}, [%[pcm]]!\n"
+ "vuzp.16 d20, d21\n"
+ "vswp d5, d20\n"
+ "vtbl.8 d16, {d4, d5}, d0\n"
+ "vtbl.8 d17, {d4, d5}, d1\n"
+ "vtbl.8 d18, {d20, d21}, d0\n"
+ "vtbl.8 d19, {d20, d21}, d1\n"
+ "vst1.16 {d16, d17}, [%[x], :128]\n"
+ "vst1.16 {d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #8\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else if (nchannels > 1) {
+ /* proper 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ asm volatile (
+ "vld1.8 {d0, d1}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #16\n"
+ "sub %[y], %[y], #16\n"
+ "sub %[position], %[position], #8\n"
+ "vld2.16 {d4, d5}, [%[pcm]]!\n"
+ "vld2.16 {d20, d21}, [%[pcm]]!\n"
+ "vswp d5, d20\n"
+ "vtbl.8 d16, {d4, d5}, d0\n"
+ "vtbl.8 d17, {d4, d5}, d1\n"
+ "vtbl.8 d18, {d20, d21}, d0\n"
+ "vtbl.8 d19, {d20, d21}, d1\n"
+ "vst1.16 {d16, d17}, [%[x], :128]\n"
+ "vst1.16 {d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #8\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else {
+ int16_t *x = &X[0][position];
+ asm volatile (
+ "vld1.8 {d0, d1}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #16\n"
+ "sub %[position], %[position], #8\n"
+ "vld1.8 {d4, d5}, [%[pcm]]!\n"
+ "vtbl.8 d16, {d4, d5}, d0\n"
+ "vtbl.8 d17, {d4, d5}, d1\n"
+ "vst1.16 {d16, d17}, [%[x], :128]\n"
+ "subs %[nsamples], %[nsamples], #8\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+ }
+ return position;
+}
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
+ int position,
+ const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels, int big_endian)
+{
+ static SBC_ALIGNED uint8_t perm_be[4][8] = {
+ PERM_BE(15, 7, 14, 8),
+ PERM_BE(13, 9, 12, 10),
+ PERM_BE(11, 3, 6, 0),
+ PERM_BE(5, 1, 4, 2)
+ };
+ static SBC_ALIGNED uint8_t perm_le[4][8] = {
+ PERM_LE(15, 7, 14, 8),
+ PERM_LE(13, 9, 12, 10),
+ PERM_LE(11, 3, 6, 0),
+ PERM_LE(5, 1, 4, 2)
+ };
+ /* handle X buffer wraparound */
+ if (position < nsamples) {
+ int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 72];
+ int16_t *src = &X[0][position];
+ asm volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1}, [%[dst], :128]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ if (nchannels > 1) {
+ dst = &X[1][SBC_X_BUFFER_SIZE - 72];
+ src = &X[1][position];
+ asm volatile (
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+ "vld1.16 {d0, d1}, [%[src], :128]!\n"
+ "vst1.16 {d0, d1}, [%[dst], :128]!\n"
+ :
+ [dst] "+r" (dst),
+ [src] "+r" (src)
+ : : "memory", "d0", "d1", "d2", "d3");
+ }
+ position = SBC_X_BUFFER_SIZE - 72;
+ }
+
+ if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+ /* poor 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ asm volatile (
+ "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #32\n"
+ "sub %[y], %[y], #32\n"
+ "sub %[position], %[position], #16\n"
+ "vld1.8 {d4, d5, d6, d7}, [%[pcm]]!\n"
+ "vuzp.16 q2, q3\n"
+ "vld1.8 {d20, d21, d22, d23}, [%[pcm]]!\n"
+ "vuzp.16 q10, q11\n"
+ "vswp q3, q10\n"
+ "vtbl.8 d16, {d4, d5, d6, d7}, d0\n"
+ "vtbl.8 d17, {d4, d5, d6, d7}, d1\n"
+ "vtbl.8 d18, {d4, d5, d6, d7}, d2\n"
+ "vtbl.8 d19, {d4, d5, d6, d7}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+ "vtbl.8 d16, {d20, d21, d22, d23}, d0\n"
+ "vtbl.8 d17, {d20, d21, d22, d23}, d1\n"
+ "vtbl.8 d18, {d20, d21, d22, d23}, d2\n"
+ "vtbl.8 d19, {d20, d21, d22, d23}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #16\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else if (nchannels > 1) {
+ /* proper 'pcm' alignment */
+ int16_t *x = &X[0][position];
+ int16_t *y = &X[1][position];
+ asm volatile (
+ "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #32\n"
+ "sub %[y], %[y], #32\n"
+ "sub %[position], %[position], #16\n"
+ "vld2.16 {d4, d5, d6, d7}, [%[pcm]]!\n"
+ "vld2.16 {d20, d21, d22, d23}, [%[pcm]]!\n"
+ "vswp q3, q10\n"
+ "vtbl.8 d16, {d4, d5, d6, d7}, d0\n"
+ "vtbl.8 d17, {d4, d5, d6, d7}, d1\n"
+ "vtbl.8 d18, {d4, d5, d6, d7}, d2\n"
+ "vtbl.8 d19, {d4, d5, d6, d7}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+ "vtbl.8 d16, {d20, d21, d22, d23}, d0\n"
+ "vtbl.8 d17, {d20, d21, d22, d23}, d1\n"
+ "vtbl.8 d18, {d20, d21, d22, d23}, d2\n"
+ "vtbl.8 d19, {d20, d21, d22, d23}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+ "subs %[nsamples], %[nsamples], #16\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [y] "+r" (y),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+ "d20", "d21", "d22", "d23");
+ } else {
+ int16_t *x = &X[0][position];
+ asm volatile (
+ "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n"
+ "1:\n"
+ "sub %[x], %[x], #32\n"
+ "sub %[position], %[position], #16\n"
+ "vld1.8 {d4, d5, d6, d7}, [%[pcm]]!\n"
+ "vtbl.8 d16, {d4, d5, d6, d7}, d0\n"
+ "vtbl.8 d17, {d4, d5, d6, d7}, d1\n"
+ "vtbl.8 d18, {d4, d5, d6, d7}, d2\n"
+ "vtbl.8 d19, {d4, d5, d6, d7}, d3\n"
+ "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+ "subs %[nsamples], %[nsamples], #16\n"
+ "bgt 1b\n"
+ :
+ [x] "+r" (x),
+ [pcm] "+r" (pcm),
+ [nsamples] "+r" (nsamples),
+ [position] "+r" (position)
+ :
+ [perm] "r" (big_endian ? perm_be : perm_le)
+ : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+ "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+ }
+ return position;
+}
+
+#undef PERM_BE
+#undef PERM_LE
+
+static int sbc_enc_process_input_4s_be_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_4s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_4s_le_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_4s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 0);
+}
+
+static int sbc_enc_process_input_8s_be_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_8s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_8s_le_neon(int position, const uint8_t *pcm,
+ int16_t X[2][SBC_X_BUFFER_SIZE],
+ int nsamples, int nchannels)
+{
+ return sbc_enc_process_input_8s_neon_internal(
+ position, pcm, X, nsamples, nchannels, 0);
+}
+
+void sbc_init_primitives_neon(struct sbc_encoder_state *state)
+{
+ state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_neon;
+ state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_neon;
+ state->sbc_calc_scalefactors = sbc_calc_scalefactors_neon;
+ state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j_neon;
+ state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le_neon;
+ state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be_neon;
+ state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le_neon;
+ state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be_neon;
+ state->implementation_info = "NEON";
+}
+
+#endif
diff --git a/src/modules/bluetooth/sbc_primitives_neon.h b/src/modules/bluetooth/sbc/sbc_primitives_neon.h
index 30766ed8..30766ed8 100644
--- a/src/modules/bluetooth/sbc_primitives_neon.h
+++ b/src/modules/bluetooth/sbc/sbc_primitives_neon.h
diff --git a/src/modules/bluetooth/sbc_tables.h b/src/modules/bluetooth/sbc/sbc_tables.h
index 0057c73f..0057c73f 100644
--- a/src/modules/bluetooth/sbc_tables.h
+++ b/src/modules/bluetooth/sbc/sbc_tables.h
diff --git a/src/modules/bluetooth/sbc_primitives_neon.c b/src/modules/bluetooth/sbc_primitives_neon.c
deleted file mode 100644
index f1bc7b48..00000000
--- a/src/modules/bluetooth/sbc_primitives_neon.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- *
- * Bluetooth low-complexity, subband codec (SBC) library
- *
- * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
- * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
- * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include <stdint.h>
-#include <limits.h>
-#include "sbc.h"
-#include "sbc_math.h"
-#include "sbc_tables.h"
-
-#include "sbc_primitives_neon.h"
-
-/*
- * ARM NEON optimizations
- */
-
-#ifdef SBC_BUILD_WITH_NEON_SUPPORT
-
-static inline void _sbc_analyze_four_neon(const int16_t *in, int32_t *out,
- const FIXED_T *consts)
-{
- /* TODO: merge even and odd cases (or even merge all four calls to this
- * function) in order to have only aligned reads from 'in' array
- * and reduce number of load instructions */
- asm volatile (
- "vld1.16 {d4, d5}, [%0, :64]!\n"
- "vld1.16 {d8, d9}, [%1, :128]!\n"
-
- "vmull.s16 q0, d4, d8\n"
- "vld1.16 {d6, d7}, [%0, :64]!\n"
- "vmull.s16 q1, d5, d9\n"
- "vld1.16 {d10, d11}, [%1, :128]!\n"
-
- "vmlal.s16 q0, d6, d10\n"
- "vld1.16 {d4, d5}, [%0, :64]!\n"
- "vmlal.s16 q1, d7, d11\n"
- "vld1.16 {d8, d9}, [%1, :128]!\n"
-
- "vmlal.s16 q0, d4, d8\n"
- "vld1.16 {d6, d7}, [%0, :64]!\n"
- "vmlal.s16 q1, d5, d9\n"
- "vld1.16 {d10, d11}, [%1, :128]!\n"
-
- "vmlal.s16 q0, d6, d10\n"
- "vld1.16 {d4, d5}, [%0, :64]!\n"
- "vmlal.s16 q1, d7, d11\n"
- "vld1.16 {d8, d9}, [%1, :128]!\n"
-
- "vmlal.s16 q0, d4, d8\n"
- "vmlal.s16 q1, d5, d9\n"
-
- "vpadd.s32 d0, d0, d1\n"
- "vpadd.s32 d1, d2, d3\n"
-
- "vrshrn.s32 d0, q0, %3\n"
-
- "vld1.16 {d2, d3, d4, d5}, [%1, :128]!\n"
-
- "vdup.i32 d1, d0[1]\n" /* TODO: can be eliminated */
- "vdup.i32 d0, d0[0]\n" /* TODO: can be eliminated */
-
- "vmull.s16 q3, d2, d0\n"
- "vmull.s16 q4, d3, d0\n"
- "vmlal.s16 q3, d4, d1\n"
- "vmlal.s16 q4, d5, d1\n"
-
- "vpadd.s32 d0, d6, d7\n" /* TODO: can be eliminated */
- "vpadd.s32 d1, d8, d9\n" /* TODO: can be eliminated */
-
- "vst1.32 {d0, d1}, [%2, :128]\n"
- : "+r" (in), "+r" (consts)
- : "r" (out),
- "i" (SBC_PROTO_FIXED4_SCALE)
- : "memory",
- "d0", "d1", "d2", "d3", "d4", "d5",
- "d6", "d7", "d8", "d9", "d10", "d11");
-}
-
-static inline void _sbc_analyze_eight_neon(const int16_t *in, int32_t *out,
- const FIXED_T *consts)
-{
- /* TODO: merge even and odd cases (or even merge all four calls to this
- * function) in order to have only aligned reads from 'in' array
- * and reduce number of load instructions */
- asm volatile (
- "vld1.16 {d4, d5}, [%0, :64]!\n"
- "vld1.16 {d8, d9}, [%1, :128]!\n"
-
- "vmull.s16 q6, d4, d8\n"
- "vld1.16 {d6, d7}, [%0, :64]!\n"
- "vmull.s16 q7, d5, d9\n"
- "vld1.16 {d10, d11}, [%1, :128]!\n"
- "vmull.s16 q8, d6, d10\n"
- "vld1.16 {d4, d5}, [%0, :64]!\n"
- "vmull.s16 q9, d7, d11\n"
- "vld1.16 {d8, d9}, [%1, :128]!\n"
-
- "vmlal.s16 q6, d4, d8\n"
- "vld1.16 {d6, d7}, [%0, :64]!\n"
- "vmlal.s16 q7, d5, d9\n"
- "vld1.16 {d10, d11}, [%1, :128]!\n"
- "vmlal.s16 q8, d6, d10\n"
- "vld1.16 {d4, d5}, [%0, :64]!\n"
- "vmlal.s16 q9, d7, d11\n"
- "vld1.16 {d8, d9}, [%1, :128]!\n"
-
- "vmlal.s16 q6, d4, d8\n"
- "vld1.16 {d6, d7}, [%0, :64]!\n"
- "vmlal.s16 q7, d5, d9\n"
- "vld1.16 {d10, d11}, [%1, :128]!\n"
- "vmlal.s16 q8, d6, d10\n"
- "vld1.16 {d4, d5}, [%0, :64]!\n"
- "vmlal.s16 q9, d7, d11\n"
- "vld1.16 {d8, d9}, [%1, :128]!\n"
-
- "vmlal.s16 q6, d4, d8\n"
- "vld1.16 {d6, d7}, [%0, :64]!\n"
- "vmlal.s16 q7, d5, d9\n"
- "vld1.16 {d10, d11}, [%1, :128]!\n"
- "vmlal.s16 q8, d6, d10\n"
- "vld1.16 {d4, d5}, [%0, :64]!\n"
- "vmlal.s16 q9, d7, d11\n"
- "vld1.16 {d8, d9}, [%1, :128]!\n"
-
- "vmlal.s16 q6, d4, d8\n"
- "vld1.16 {d6, d7}, [%0, :64]!\n"
- "vmlal.s16 q7, d5, d9\n"
- "vld1.16 {d10, d11}, [%1, :128]!\n"
-
- "vmlal.s16 q8, d6, d10\n"
- "vmlal.s16 q9, d7, d11\n"
-
- "vpadd.s32 d0, d12, d13\n"
- "vpadd.s32 d1, d14, d15\n"
- "vpadd.s32 d2, d16, d17\n"
- "vpadd.s32 d3, d18, d19\n"
-
- "vrshr.s32 q0, q0, %3\n"
- "vrshr.s32 q1, q1, %3\n"
- "vmovn.s32 d0, q0\n"
- "vmovn.s32 d1, q1\n"
-
- "vdup.i32 d3, d1[1]\n" /* TODO: can be eliminated */
- "vdup.i32 d2, d1[0]\n" /* TODO: can be eliminated */
- "vdup.i32 d1, d0[1]\n" /* TODO: can be eliminated */
- "vdup.i32 d0, d0[0]\n" /* TODO: can be eliminated */
-
- "vld1.16 {d4, d5}, [%1, :128]!\n"
- "vmull.s16 q6, d4, d0\n"
- "vld1.16 {d6, d7}, [%1, :128]!\n"
- "vmull.s16 q7, d5, d0\n"
- "vmull.s16 q8, d6, d0\n"
- "vmull.s16 q9, d7, d0\n"
-
- "vld1.16 {d4, d5}, [%1, :128]!\n"
- "vmlal.s16 q6, d4, d1\n"
- "vld1.16 {d6, d7}, [%1, :128]!\n"
- "vmlal.s16 q7, d5, d1\n"
- "vmlal.s16 q8, d6, d1\n"
- "vmlal.s16 q9, d7, d1\n"
-
- "vld1.16 {d4, d5}, [%1, :128]!\n"
- "vmlal.s16 q6, d4, d2\n"
- "vld1.16 {d6, d7}, [%1, :128]!\n"
- "vmlal.s16 q7, d5, d2\n"
- "vmlal.s16 q8, d6, d2\n"
- "vmlal.s16 q9, d7, d2\n"
-
- "vld1.16 {d4, d5}, [%1, :128]!\n"
- "vmlal.s16 q6, d4, d3\n"
- "vld1.16 {d6, d7}, [%1, :128]!\n"
- "vmlal.s16 q7, d5, d3\n"
- "vmlal.s16 q8, d6, d3\n"
- "vmlal.s16 q9, d7, d3\n"
-
- "vpadd.s32 d0, d12, d13\n" /* TODO: can be eliminated */
- "vpadd.s32 d1, d14, d15\n" /* TODO: can be eliminated */
- "vpadd.s32 d2, d16, d17\n" /* TODO: can be eliminated */
- "vpadd.s32 d3, d18, d19\n" /* TODO: can be eliminated */
-
- "vst1.32 {d0, d1, d2, d3}, [%2, :128]\n"
- : "+r" (in), "+r" (consts)
- : "r" (out),
- "i" (SBC_PROTO_FIXED8_SCALE)
- : "memory",
- "d0", "d1", "d2", "d3", "d4", "d5",
- "d6", "d7", "d8", "d9", "d10", "d11",
- "d12", "d13", "d14", "d15", "d16", "d17",
- "d18", "d19");
-}
-
-static inline void sbc_analyze_4b_4s_neon(int16_t *x,
- int32_t *out, int out_stride)
-{
- /* Analyze blocks */
- _sbc_analyze_four_neon(x + 12, out, analysis_consts_fixed4_simd_odd);
- out += out_stride;
- _sbc_analyze_four_neon(x + 8, out, analysis_consts_fixed4_simd_even);
- out += out_stride;
- _sbc_analyze_four_neon(x + 4, out, analysis_consts_fixed4_simd_odd);
- out += out_stride;
- _sbc_analyze_four_neon(x + 0, out, analysis_consts_fixed4_simd_even);
-}
-
-static inline void sbc_analyze_4b_8s_neon(int16_t *x,
- int32_t *out, int out_stride)
-{
- /* Analyze blocks */
- _sbc_analyze_eight_neon(x + 24, out, analysis_consts_fixed8_simd_odd);
- out += out_stride;
- _sbc_analyze_eight_neon(x + 16, out, analysis_consts_fixed8_simd_even);
- out += out_stride;
- _sbc_analyze_eight_neon(x + 8, out, analysis_consts_fixed8_simd_odd);
- out += out_stride;
- _sbc_analyze_eight_neon(x + 0, out, analysis_consts_fixed8_simd_even);
-}
-
-void sbc_init_primitives_neon(struct sbc_encoder_state *state)
-{
- state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_neon;
- state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_neon;
- state->implementation_info = "NEON";
-}
-
-#endif
diff --git a/src/modules/coreaudio/module-coreaudio-detect.c b/src/modules/coreaudio/module-coreaudio-detect.c
index c23079a9..1d26b84e 100644
--- a/src/modules/coreaudio/module-coreaudio-detect.c
+++ b/src/modules/coreaudio/module-coreaudio-detect.c
@@ -47,7 +47,7 @@ typedef struct ca_device ca_device;
struct ca_device {
AudioObjectID id;
- unsigned int module_index;
+ unsigned int module_index;
PA_LLIST_FIELDS(ca_device);
};
@@ -162,7 +162,7 @@ scan_removed:
}
if (!found) {
- pa_log_debug("object id %d has been removed (module index %d) %p", (unsigned int) dev->id, dev->module_index, dev);
+ pa_log_debug("object id %d has been removed (module index %d) %p", (unsigned int) dev->id, dev->module_index, dev);
pa_module_unload_request_by_index(m->core, dev->module_index, TRUE);
PA_LLIST_REMOVE(ca_device, u->devices, dev);
pa_xfree(dev);
diff --git a/src/modules/coreaudio/module-coreaudio-device.c b/src/modules/coreaudio/module-coreaudio-device.c
index 5e6d49c2..cc4600b5 100644
--- a/src/modules/coreaudio/module-coreaudio-device.c
+++ b/src/modules/coreaudio/module-coreaudio-device.c
@@ -747,7 +747,7 @@ int pa__init(pa_module *m) {
ca_device_create_streams(m, TRUE);
/* create the message thread */
- if (!(u->thread = pa_thread_new(thread_func, u))) {
+ if (!(u->thread = pa_thread_new("coreaudio", thread_func, u))) {
pa_log("Failed to create thread.");
goto fail;
}
diff --git a/src/modules/dbus/iface-device.c b/src/modules/dbus/iface-device.c
index a8652df9..c5ba88e0 100644
--- a/src/modules/dbus/iface-device.c
+++ b/src/modules/dbus/iface-device.c
@@ -422,21 +422,20 @@ static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessag
pa_assert(iter);
pa_assert(d);
- pa_cvolume_init(&new_vol);
-
device_channels = (d->type == DEVICE_TYPE_SINK) ? d->sink->channel_map.channels : d->source->channel_map.channels;
- new_vol.channels = device_channels;
-
dbus_message_iter_recurse(iter, &array_iter);
dbus_message_iter_get_fixed_array(&array_iter, &volume, &n_volume_entries);
- if (n_volume_entries != device_channels) {
+ if (n_volume_entries != device_channels && n_volume_entries != 1) {
pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
"Expected %u volume entries, got %i.", device_channels, n_volume_entries);
return;
}
+ pa_cvolume_init(&new_vol);
+ new_vol.channels = n_volume_entries;
+
for (i = 0; i < n_volume_entries; ++i) {
if (!PA_VOLUME_IS_VALID(volume[i])) {
pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Too large volume value: %u", volume[i]);
diff --git a/src/modules/dbus/iface-stream.c b/src/modules/dbus/iface-stream.c
index 681790b7..e3464fdf 100644
--- a/src/modules/dbus/iface-stream.c
+++ b/src/modules/dbus/iface-stream.c
@@ -56,6 +56,9 @@ struct pa_dbusiface_stream {
dbus_bool_t mute;
pa_proplist *proplist;
+ pa_bool_t has_volume;
+ pa_bool_t read_only_volume;
+
pa_dbus_protocol *dbus_protocol;
pa_subscription *subscription;
pa_hook_slot *send_event_slot;
@@ -189,6 +192,14 @@ static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userd
pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
}
+/* The returned string has to be freed with pa_xfree() by the caller. */
+static char *stream_to_string(pa_dbusiface_stream *s) {
+ if (s->type == STREAM_TYPE_PLAYBACK)
+ return pa_sprintf_malloc("Playback stream %u", (unsigned) s->sink_input->index);
+ else
+ return pa_sprintf_malloc("Record stream %u", (unsigned) s->source_output->index);
+}
+
static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) {
pa_dbusiface_stream *s = userdata;
const char *driver = NULL;
@@ -200,12 +211,11 @@ static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *user
driver = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->driver : s->source_output->driver;
if (!driver) {
- if (s->type == STREAM_TYPE_PLAYBACK)
- pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
- "Playback stream %u doesn't have a driver.", s->sink_input->index);
- else
- pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
- "Record stream %u doesn't have a driver.", s->source_output->index);
+ char *str = stream_to_string(s);
+
+ pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have a driver.", str);
+ pa_xfree(str);
+
return;
}
@@ -224,12 +234,11 @@ static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void
owner_module = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->module : s->source_output->module;
if (!owner_module) {
- if (s->type == STREAM_TYPE_PLAYBACK)
- pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
- "Playback stream %u doesn't have an owner module.", s->sink_input->index);
- else
- pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
- "Record stream %u doesn't have an owner module.", s->source_output->index);
+ char *str = stream_to_string(s);
+
+ pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have an owner module.", str);
+ pa_xfree(str);
+
return;
}
@@ -250,12 +259,11 @@ static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *user
client = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->client : s->source_output->client;
if (!client) {
- if (s->type == STREAM_TYPE_PLAYBACK)
- pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
- "Playback stream %u isn't associated to any client.", s->sink_input->index);
- else
- pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
- "Record stream %u isn't associated to any client.", s->source_output->index);
+ char *str = stream_to_string(s);
+
+ pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s isn't associated to any client.", str);
+ pa_xfree(str);
+
return;
}
@@ -332,8 +340,12 @@ static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *user
pa_assert(msg);
pa_assert(s);
- if (s->type == STREAM_TYPE_RECORD) {
- pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have volume.");
+ if (!s->has_volume) {
+ char *str = stream_to_string(s);
+
+ pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str);
+ pa_xfree(str);
+
return;
}
@@ -357,26 +369,32 @@ static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessag
pa_assert(iter);
pa_assert(s);
- if (s->type == STREAM_TYPE_RECORD) {
- pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have volume.");
+ if (!s->has_volume || s->read_only_volume) {
+ char *str = stream_to_string(s);
+
+ if (!s->has_volume)
+ pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str);
+ else if (s->read_only_volume)
+ pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "%s has read-only volume.", str);
+ pa_xfree(str);
+
return;
}
- pa_cvolume_init(&new_vol);
-
stream_channels = s->sink_input->channel_map.channels;
- new_vol.channels = stream_channels;
-
dbus_message_iter_recurse(iter, &array_iter);
dbus_message_iter_get_fixed_array(&array_iter, &volume, &n_volume_entries);
- if (n_volume_entries != stream_channels) {
+ if (n_volume_entries != stream_channels && n_volume_entries != 1) {
pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
"Expected %u volume entries, got %u.", stream_channels, n_volume_entries);
return;
}
+ pa_cvolume_init(&new_vol);
+ new_vol.channels = n_volume_entries;
+
for (i = 0; i < n_volume_entries; ++i) {
if (!PA_VOLUME_IS_VALID(volume[i])) {
pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume: %u", volume[i]);
@@ -471,6 +489,9 @@ static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, v
else
resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
+ if (!resample_method)
+ resample_method = "";
+
pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &resample_method);
}
@@ -509,6 +530,11 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
pa_assert(msg);
pa_assert(s);
+ if (s->has_volume) {
+ for (i = 0; i < s->volume.channels; ++i)
+ volume[i] = s->volume.values[i];
+ }
+
if (s->type == STREAM_TYPE_PLAYBACK) {
idx = s->sink_input->index;
driver = s->sink_input->driver;
@@ -517,8 +543,6 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
sample_format = s->sink_input->sample_spec.format;
channel_map = &s->sink_input->channel_map;
- for (i = 0; i < s->volume.channels; ++i)
- volume[i] = s->volume.values[i];
buffer_latency = pa_sink_input_get_latency(s->sink_input, &device_latency);
resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
} else {
@@ -538,6 +562,8 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
client_path = pa_dbusiface_core_get_client_path(s->core, client);
for (i = 0; i < channel_map->channels; ++i)
channels[i] = channel_map->map[i];
+ if (!resample_method)
+ resample_method = "";
pa_assert_se((reply = dbus_message_new_method_return(msg)));
@@ -555,11 +581,12 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
if (client)
pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CLIENT].property_name, DBUS_TYPE_OBJECT_PATH, &client_path);
+ pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE].property_name, DBUS_TYPE_OBJECT_PATH, &device);
pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format);
pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &s->sample_rate);
pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, channel_map->channels);
- if (s->type == STREAM_TYPE_PLAYBACK) {
+ if (s->has_volume) {
pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, s->volume.channels);
pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &s->mute);
}
@@ -707,30 +734,33 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
}
if (s->type == STREAM_TYPE_PLAYBACK) {
- pa_cvolume new_volume;
pa_bool_t new_mute = FALSE;
- pa_sink_input_get_volume(s->sink_input, &new_volume, TRUE);
+ if (s->has_volume) {
+ pa_cvolume new_volume;
- if (!pa_cvolume_equal(&s->volume, &new_volume)) {
- dbus_uint32_t volume[PA_CHANNELS_MAX];
- dbus_uint32_t *volume_ptr = volume;
+ pa_sink_input_get_volume(s->sink_input, &new_volume, TRUE);
- s->volume = new_volume;
+ if (!pa_cvolume_equal(&s->volume, &new_volume)) {
+ dbus_uint32_t volume[PA_CHANNELS_MAX];
+ dbus_uint32_t *volume_ptr = volume;
- for (i = 0; i < s->volume.channels; ++i)
- volume[i] = s->volume.values[i];
+ s->volume = new_volume;
- pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
- PA_DBUSIFACE_STREAM_INTERFACE,
- signals[SIGNAL_VOLUME_UPDATED].name));
- pa_assert_se(dbus_message_append_args(signal_msg,
- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
- DBUS_TYPE_INVALID));
+ for (i = 0; i < s->volume.channels; ++i)
+ volume[i] = s->volume.values[i];
- pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
- dbus_message_unref(signal_msg);
- signal_msg = NULL;
+ pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
+ PA_DBUSIFACE_STREAM_INTERFACE,
+ signals[SIGNAL_VOLUME_UPDATED].name));
+ pa_assert_se(dbus_message_append_args(signal_msg,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
+ DBUS_TYPE_INVALID));
+
+ pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
+ dbus_message_unref(signal_msg);
+ signal_msg = NULL;
+ }
}
new_mute = pa_sink_input_get_mute(s->sink_input);
@@ -822,7 +852,14 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, p
s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, PLAYBACK_OBJECT_NAME, sink_input->index);
s->sink = pa_sink_ref(sink_input->sink);
s->sample_rate = sink_input->sample_spec.rate;
- pa_sink_input_get_volume(sink_input, &s->volume, TRUE);
+ s->has_volume = pa_sink_input_is_volume_readable(sink_input);
+ s->read_only_volume = s->has_volume ? !pa_sink_input_is_volume_writable(sink_input) : FALSE;
+
+ if (s->has_volume)
+ pa_sink_input_get_volume(sink_input, &s->volume, TRUE);
+ else
+ pa_cvolume_init(&s->volume);
+
s->mute = pa_sink_input_get_mute(sink_input);
s->proplist = pa_proplist_copy(sink_input->proplist);
s->dbus_protocol = pa_dbus_protocol_get(sink_input->core);
@@ -853,6 +890,8 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_
pa_cvolume_init(&s->volume);
s->mute = FALSE;
s->proplist = pa_proplist_copy(source_output->proplist);
+ s->has_volume = FALSE;
+ s->read_only_volume = FALSE;
s->dbus_protocol = pa_dbus_protocol_get(source_output->core);
s->subscription = pa_subscription_new(source_output->core, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscription_cb, s);
s->send_event_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT],
diff --git a/src/modules/echo-cancel/adrian.c b/src/modules/echo-cancel/adrian.c
index 446966fb..08df2edd 100644
--- a/src/modules/echo-cancel/adrian.c
+++ b/src/modules/echo-cancel/adrian.c
@@ -42,7 +42,7 @@ static const char* const valid_modargs[] = {
};
static void pa_adrian_ec_fixate_spec(pa_sample_spec *source_ss, pa_channel_map *source_map,
- pa_sample_spec *sink_ss, pa_channel_map *sink_map)
+ pa_sample_spec *sink_ss, pa_channel_map *sink_map)
{
source_ss->format = PA_SAMPLE_S16NE;
source_ss->channels = 1;
@@ -87,19 +87,18 @@ pa_bool_t pa_adrian_ec_init(pa_core *c, pa_echo_canceller *ec,
ec->params.priv.adrian.aec = AEC_init(rate, have_vector);
if (!ec->params.priv.adrian.aec)
- goto fail;
+ goto fail;
pa_modargs_free(ma);
return TRUE;
fail:
if (ma)
- pa_modargs_free(ma);
+ pa_modargs_free(ma);
return FALSE;
}
-void pa_adrian_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out)
-{
+void pa_adrian_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out) {
unsigned int i;
for (i = 0; i < ec->params.priv.adrian.blocksize; i += 2) {
@@ -110,8 +109,7 @@ void pa_adrian_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *
}
}
-void pa_adrian_ec_done(pa_echo_canceller *ec)
-{
+void pa_adrian_ec_done(pa_echo_canceller *ec) {
pa_xfree(ec->params.priv.adrian.aec);
ec->params.priv.adrian.aec = NULL;
}
diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index 611ebb71..a3ad1698 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -290,7 +290,7 @@ static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct tim
* canceler does not work in this case. */
pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_APPLY_DIFF_TIME,
NULL, diff_time, NULL, NULL);
- //new_rate = base_rate - ((pa_usec_to_bytes (-diff_time, &u->source_output->sample_spec) / fs) * PA_USEC_PER_SEC) / u->adjust_time;
+ //new_rate = base_rate - ((pa_usec_to_bytes(-diff_time, &u->source_output->sample_spec) / fs) * PA_USEC_PER_SEC) / u->adjust_time;
new_rate = base_rate;
}
else {
@@ -301,7 +301,7 @@ static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct tim
}
/* recording behind playback, we need to slowly adjust the rate to match */
- //new_rate = base_rate + ((pa_usec_to_bytes (diff_time, &u->source_output->sample_spec) / fs) * PA_USEC_PER_SEC) / u->adjust_time;
+ //new_rate = base_rate + ((pa_usec_to_bytes(diff_time, &u->source_output->sample_spec) / fs) * PA_USEC_PER_SEC) / u->adjust_time;
/* assume equal samplerates for now */
new_rate = base_rate;
@@ -404,7 +404,7 @@ static int source_set_state_cb(pa_source *s, pa_source_state_t state) {
if (u->active_mask == 3)
pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
- pa_atomic_store (&u->request_resync, 1);
+ pa_atomic_store(&u->request_resync, 1);
pa_source_output_cork(u->source_output, FALSE);
} else if (state == PA_SOURCE_SUSPENDED) {
u->active_mask &= ~1;
@@ -432,7 +432,7 @@ static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
if (u->active_mask == 3)
pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
- pa_atomic_store (&u->request_resync, 1);
+ pa_atomic_store(&u->request_resync, 1);
pa_sink_input_cork(u->sink_input, FALSE);
} else if (state == PA_SINK_SUSPENDED) {
u->active_mask &= ~2;
@@ -597,7 +597,7 @@ static void apply_diff_time(struct userdata *u, int64_t diff_time) {
int64_t diff;
if (diff_time < 0) {
- diff = pa_usec_to_bytes (-diff_time, &u->source_output->sample_spec);
+ diff = pa_usec_to_bytes(-diff_time, &u->source_output->sample_spec);
if (diff > 0) {
/* add some extra safety samples to compensate for jitter in the
@@ -610,7 +610,7 @@ static void apply_diff_time(struct userdata *u, int64_t diff_time) {
u->source_skip = 0;
}
} else if (diff_time > 0) {
- diff = pa_usec_to_bytes (diff_time, &u->source_output->sample_spec);
+ diff = pa_usec_to_bytes(diff_time, &u->source_output->sample_spec);
if (diff > 0) {
pa_log("playback too far ahead (%lld), drop source %lld", (long long) diff_time, (long long) diff);
@@ -660,7 +660,7 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk)
u->in_push = FALSE;
if (pa_atomic_cmpxchg (&u->request_resync, 1, 0)) {
- do_resync (u);
+ do_resync(u);
}
pa_memblockq_push_align(u->source_memblockq, chunk);
@@ -770,7 +770,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
if (i->thread_info.underrun_for > 0) {
pa_log_debug("Handling end of underrun.");
- pa_atomic_store (&u->request_resync, 1);
+ pa_atomic_store(&u->request_resync, 1);
}
/* let source thread handle the chunk. pass the sample count as well so that
@@ -926,7 +926,7 @@ static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
pa_log_debug("Sink input update max rewind %lld", (long long) nbytes);
- pa_memblockq_set_maxrewind (u->sink_memblockq, nbytes);
+ pa_memblockq_set_maxrewind(u->sink_memblockq, nbytes);
pa_sink_set_max_rewind_within_thread(u->sink, nbytes);
}
@@ -1300,8 +1300,7 @@ static void sink_input_mute_changed_cb(pa_sink_input *i) {
pa_sink_mute_changed(u->sink, i->muted);
}
-static pa_echo_canceller_method_t get_ec_method_from_string(const char *method)
-{
+static pa_echo_canceller_method_t get_ec_method_from_string(const char *method) {
if (strcmp(method, "speex") == 0)
return PA_ECHO_CANCELLER_SPEEX;
else if (strcmp(method, "adrian") == 0)
@@ -1502,6 +1501,7 @@ int pa__init(pa_module*m) {
source_output_data.driver = __FILE__;
source_output_data.module = m;
source_output_data.source = source_master;
+ source_output_data.destination_source = u->source;
/* FIXME
source_output_data.flags = PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND; */
@@ -1531,11 +1531,14 @@ int pa__init(pa_module*m) {
u->source_output->moving = source_output_moving_cb;
u->source_output->userdata = u;
+ u->source->output_from_master = u->source_output;
+
/* Create sink input */
pa_sink_input_new_data_init(&sink_input_data);
sink_input_data.driver = __FILE__;
sink_input_data.module = m;
sink_input_data.sink = sink_master;
+ sink_input_data.origin_sink = u->sink;
pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Echo-Cancel Sink Stream");
pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
pa_sink_input_new_data_set_sample_spec(&sink_input_data, &sink_ss);
@@ -1566,6 +1569,8 @@ int pa__init(pa_module*m) {
u->sink_input->mute_changed = sink_input_mute_changed_cb;
u->sink_input->userdata = u;
+ u->sink->input_to_master = u->sink_input;
+
pa_sink_input_get_silence(u->sink_input, &silence);
u->source_memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0,
@@ -1609,7 +1614,7 @@ int pa__init(pa_module*m) {
return 0;
- fail:
+fail:
if (ma)
pa_modargs_free(ma);
@@ -1624,7 +1629,7 @@ int pa__get_n_used(pa_module *m) {
pa_assert(m);
pa_assert_se(u = m->userdata);
- return pa_sink_linked_by(u->sink) + pa_source_linked_by(u->source);
+ return pa_sink_linked_by(u->sink) + pa_source_linked_by(u->source);
}
void pa__done(pa_module*m) {
diff --git a/src/modules/echo-cancel/speex.c b/src/modules/echo-cancel/speex.c
index 7851510b..ce361fc3 100644
--- a/src/modules/echo-cancel/speex.c
+++ b/src/modules/echo-cancel/speex.c
@@ -40,7 +40,7 @@ static const char* const valid_modargs[] = {
};
static void pa_speex_ec_fixate_spec(pa_sample_spec *source_ss, pa_channel_map *source_map,
- pa_sample_spec *sink_ss, pa_channel_map *sink_map)
+ pa_sample_spec *sink_ss, pa_channel_map *sink_map)
{
source_ss->format = PA_SAMPLE_S16NE;
@@ -91,7 +91,7 @@ pa_bool_t pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec,
ec->params.priv.speex.state = speex_echo_state_init_mc (framelen, (rate * filter_size_ms) / 1000, source_ss->channels, source_ss->channels);
if (!ec->params.priv.speex.state)
- goto fail;
+ goto fail;
speex_echo_ctl(ec->params.priv.speex.state, SPEEX_ECHO_SET_SAMPLING_RATE, &rate);
@@ -100,17 +100,15 @@ pa_bool_t pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec,
fail:
if (ma)
- pa_modargs_free(ma);
+ pa_modargs_free(ma);
return FALSE;
}
-void pa_speex_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out)
-{
+void pa_speex_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out) {
speex_echo_cancellation(ec->params.priv.speex.state, (const spx_int16_t *) rec, (const spx_int16_t *) play, (spx_int16_t *) out);
}
-void pa_speex_ec_done(pa_echo_canceller *ec)
-{
- speex_echo_state_destroy (ec->params.priv.speex.state);
+void pa_speex_ec_done(pa_echo_canceller *ec) {
+ speex_echo_state_destroy(ec->params.priv.speex.state);
ec->params.priv.speex.state = NULL;
}
diff --git a/src/modules/jack/module-jack-sink.c b/src/modules/jack/module-jack-sink.c
index 08a8befa..0b4e7ee4 100644
--- a/src/modules/jack/module-jack-sink.c
+++ b/src/modules/jack/module-jack-sink.c
@@ -68,7 +68,7 @@ PA_MODULE_LOAD_ONCE(TRUE);
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_USAGE(
"sink_name=<name for the sink> "
- "sink_properties=<properties for the card> "
+ "sink_properties=<properties for the card> "
"server_name=<jack server name> "
"client_name=<jack client name> "
"channels=<number of channels> "
diff --git a/src/modules/jack/module-jackdbus-detect.c b/src/modules/jack/module-jackdbus-detect.c
index f635b233..c3dd7bb2 100644
--- a/src/modules/jack/module-jackdbus-detect.c
+++ b/src/modules/jack/module-jackdbus-detect.c
@@ -84,8 +84,7 @@ struct userdata {
};
-static void ensure_ports_stopped(struct userdata* u)
-{
+static void ensure_ports_stopped(struct userdata* u) {
int i;
pa_assert(u);
@@ -97,8 +96,7 @@ static void ensure_ports_stopped(struct userdata* u)
}
}
-static void ensure_ports_started(struct userdata* u)
-{
+static void ensure_ports_started(struct userdata* u) {
int i;
pa_assert(u);
@@ -120,8 +118,7 @@ static void ensure_ports_started(struct userdata* u)
}
-static pa_bool_t check_service_started(struct userdata* u)
-{
+static pa_bool_t check_service_started(struct userdata* u) {
DBusError error;
DBusMessage *m = NULL, *reply = NULL;
pa_bool_t new_status = FALSE;
@@ -169,8 +166,7 @@ finish:
return new_status;
}
-static DBusHandlerResult dbus_filter_handler(DBusConnection *c, DBusMessage *s, void *userdata)
-{
+static DBusHandlerResult dbus_filter_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
struct userdata *u = NULL;
DBusError error;
@@ -182,13 +178,11 @@ static DBusHandlerResult dbus_filter_handler(DBusConnection *c, DBusMessage *s,
if (dbus_message_is_signal(s, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
const char *name, *old, *new;
- if (!dbus_message_get_args(
- s,
- &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &old,
- DBUS_TYPE_STRING, &new,
- DBUS_TYPE_INVALID))
+ if (!dbus_message_get_args(s, &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &old,
+ DBUS_TYPE_STRING, &new,
+ DBUS_TYPE_INVALID))
goto finish;
if (strcmp(name, JACK_SERVICE_NAME))
goto finish;
@@ -211,8 +205,7 @@ finish:
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
-int pa__init(pa_module *m)
-{
+int pa__init(pa_module *m) {
DBusError error;
pa_dbus_connection *connection = NULL;
struct userdata *u = NULL;
@@ -275,8 +268,7 @@ fail:
return -1;
}
-void pa__done(pa_module *m)
-{
+void pa__done(pa_module *m) {
struct userdata *u;
pa_assert(m);
diff --git a/src/modules/module-augment-properties.c b/src/modules/module-augment-properties.c
index bdeee291..c3f5c088 100644
--- a/src/modules/module-augment-properties.c
+++ b/src/modules/module-augment-properties.c
@@ -25,6 +25,7 @@
#include <sys/stat.h>
#include <dirent.h>
+#include <time.h>
#include <pulse/xmalloc.h>
#include <pulse/volume.h>
@@ -190,9 +191,7 @@ static void update_rule(struct rule *r) {
continue;
pa_xfree(fn);
- fn = pa_sprintf_malloc(DESKTOPFILEDIR
- PA_PATH_SEP "%s" PA_PATH_SEP "%s.desktop",
- dir->d_name, r->process_name);
+ fn = pa_sprintf_malloc(DESKTOPFILEDIR PA_PATH_SEP "%s" PA_PATH_SEP "%s.desktop", dir->d_name, r->process_name);
if (stat(fn, &st) == 0) {
found = TRUE;
@@ -357,7 +356,7 @@ fail:
if (ma)
pa_modargs_free(ma);
- return -1;
+ return -1;
}
void pa__done(pa_module *m) {
diff --git a/src/modules/module-card-restore.c b/src/modules/module-card-restore.c
index 7c20ce31..ed0a31df 100644
--- a/src/modules/module-card-restore.c
+++ b/src/modules/module-card-restore.c
@@ -251,7 +251,7 @@ fail:
if (ma)
pa_modargs_free(ma);
- return -1;
+ return -1;
}
void pa__done(pa_module*m) {
diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c
index 3104ed68..ab93c05e 100644
--- a/src/modules/module-combine.c
+++ b/src/modules/module-combine.c
@@ -557,7 +557,7 @@ static int sink_input_process_msg(pa_msgobject *obj, int code, void *data, int64
switch (code) {
case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
- pa_usec_t *r = data;
+ pa_usec_t *r = data;
*r = pa_bytes_to_usec(pa_memblockq_get_length(o->memblockq), &o->sink_input->sample_spec);
diff --git a/src/modules/module-console-kit.c b/src/modules/module-console-kit.c
index 875852f3..d52cc244 100644
--- a/src/modules/module-console-kit.c
+++ b/src/modules/module-console-kit.c
@@ -77,7 +77,7 @@ static void add_session(struct userdata *u, const char *id) {
struct session *session;
pa_client_new_data data;
- dbus_error_init (&error);
+ dbus_error_init(&error);
if (pa_hashmap_get(u->sessions, id)) {
pa_log_warn("Duplicate session %s, ignoring.", id);
diff --git a/src/modules/module-cork-music-on-phone.c b/src/modules/module-cork-music-on-phone.c
index d3a2b00e..b629f06f 100644
--- a/src/modules/module-cork-music-on-phone.c
+++ b/src/modules/module-cork-music-on-phone.c
@@ -66,8 +66,10 @@ static pa_bool_t shall_cork(pa_sink *s, pa_sink_input *ignore) {
if (!(role = pa_proplist_gets(j->proplist, PA_PROP_MEDIA_ROLE)))
continue;
- if (pa_streq(role, "phone"))
+ if (pa_streq(role, "phone")) {
+ pa_log_debug("Found a phone stream that will trigger the auto-cork.");
return TRUE;
+ }
}
return FALSE;
@@ -81,7 +83,7 @@ static void apply_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa
pa_sink_assert_ref(s);
for (j = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); j; j = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
- pa_bool_t corked;
+ pa_bool_t corked, muted, corked_here;
const char *role;
if (j == ignore)
@@ -94,18 +96,25 @@ static void apply_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa
!pa_streq(role, "music"))
continue;
- corked = !!pa_hashmap_get(u->cork_state, j);
+ corked = (pa_sink_input_get_state(j) == PA_SINK_INPUT_CORKED);
+ muted = pa_sink_input_get_mute(j);
+ corked_here = !!pa_hashmap_get(u->cork_state, j);
- if (cork && !corked) {
- pa_hashmap_put(u->cork_state, j, PA_INT_TO_PTR(1));
+ if (cork && !corked && !muted) {
+ pa_log_debug("Found a music/video stream that should be corked/muted.");
+ if (!corked_here)
+ pa_hashmap_put(u->cork_state, j, PA_INT_TO_PTR(1));
pa_sink_input_set_mute(j, TRUE, FALSE);
pa_sink_input_send_event(j, PA_STREAM_EVENT_REQUEST_CORK, NULL);
} else if (!cork) {
pa_hashmap_remove(u->cork_state, j);
- if (corked) {
- pa_sink_input_set_mute(j, FALSE, FALSE);
- pa_sink_input_send_event(j, PA_STREAM_EVENT_REQUEST_UNCORK, NULL);
+ if (corked_here && (corked || muted)) {
+ pa_log_debug("Found a music/video stream that should be uncorked/unmuted.");
+ if (muted)
+ pa_sink_input_set_mute(j, FALSE, FALSE);
+ if (corked)
+ pa_sink_input_send_event(j, PA_STREAM_EVENT_REQUEST_UNCORK, NULL);
}
}
}
@@ -193,7 +202,7 @@ fail:
if (ma)
pa_modargs_free(ma);
- return -1;
+ return -1;
}
diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c
index 1fe8eb8b..2a90eb63 100644
--- a/src/modules/module-detect.c
+++ b/src/modules/module-detect.c
@@ -144,7 +144,7 @@ static int detect_oss(pa_core *c, int just_one) {
line[strcspn(line, "\r\n")] = 0;
if (!b) {
- b = strcmp(line, "Audio devices:") == 0 || strcmp(line, "Installed devices:") == 0;
+ b = strcmp(line, "Audio devices:") == 0 || strcmp(line, "Installed devices:") == 0;
continue;
}
diff --git a/src/modules/module-device-manager.c b/src/modules/module-device-manager.c
index eda6787e..47469b06 100644
--- a/src/modules/module-device-manager.c
+++ b/src/modules/module-device-manager.c
@@ -698,7 +698,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
pa_strlcpy(entry.icon, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME)), sizeof(entry.icon));
- } else if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE) {
+ } else if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE) {
pa_source *source;
pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
@@ -1174,7 +1174,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
goto fail;
if (PA_INVALID_INDEX == (role_index = get_role_index(role)))
- goto fail;
+ goto fail;
/* Cycle through the devices given and make sure they exist */
h = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
@@ -1209,9 +1209,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
if (first) {
first = FALSE;
sink_mode = (0 == strncmp("sink:", s, 5));
- } else if ((sink_mode && 0 != strncmp("sink:", s, 5))
- || (!sink_mode && 0 != strncmp("source:", s, 7)))
- {
+ } else if ((sink_mode && 0 != strncmp("sink:", s, 5)) || (!sink_mode && 0 != strncmp("source:", s, 7))) {
while ((device = pa_hashmap_steal_first(h))) {
pa_xfree(device->device);
pa_xfree(device);
@@ -1542,7 +1540,7 @@ fail:
if (ma)
pa_modargs_free(ma);
- return -1;
+ return -1;
}
void pa__done(pa_module*m) {
diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c
index fcd3ccf6..4c31a985 100644
--- a/src/modules/module-device-restore.c
+++ b/src/modules/module-device-restore.c
@@ -514,7 +514,7 @@ fail:
if (ma)
pa_modargs_free(ma);
- return -1;
+ return -1;
}
void pa__done(pa_module*m) {
diff --git a/src/modules/module-equalizer-sink.c b/src/modules/module-equalizer-sink.c
index bc349ce0..bb350c38 100644
--- a/src/modules/module-equalizer-sink.c
+++ b/src/modules/module-equalizer-sink.c
@@ -77,7 +77,8 @@ PA_MODULE_DESCRIPTION(_("General Purpose Equalizer"));
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
- _("sink_name=<name of the sink>"
+ _("sink_name=<name of the sink> "
+ "sink_properties=<properties for the sink> "
"master=<sink to connect to> "
"format=<sample format> "
"rate=<sample rate> "
@@ -131,6 +132,7 @@ struct userdata {
static const char* const valid_modargs[] = {
"sink_name",
+ "sink_properties",
"master",
"format",
"rate",
@@ -1200,6 +1202,7 @@ int pa__init(pa_module*m) {
sink_input_data.driver = __FILE__;
sink_input_data.module = m;
sink_input_data.sink = master;
+ sink_input_data.origin_sink = u->sink;
pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Equalized Stream");
pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
@@ -1225,9 +1228,10 @@ int pa__init(pa_module*m) {
u->sink_input->moving = sink_input_moving_cb;
u->sink_input->volume_changed = sink_input_volume_changed_cb;
u->sink_input->mute_changed = sink_input_mute_changed_cb;
-
u->sink_input->userdata = u;
+ u->sink->input_to_master = u->sink_input;
+
dbus_init(u);
/* default filter to these */
diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c
index 23d40100..941ac3a4 100644
--- a/src/modules/module-hal-detect.c
+++ b/src/modules/module-hal-detect.c
@@ -57,13 +57,13 @@ PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(TRUE);
#if defined(HAVE_ALSA) && defined(HAVE_OSS_OUTPUT)
PA_MODULE_USAGE("api=<alsa or oss> "
- "tsched=<enable system timer based scheduling mode?>"
+ "tsched=<enable system timer based scheduling mode?> "
"subdevices=<init all subdevices>");
#elif defined(HAVE_ALSA)
PA_MODULE_USAGE("api=<alsa> "
"tsched=<enable system timer based scheduling mode?>");
#elif defined(HAVE_OSS_OUTPUT)
-PA_MODULE_USAGE("api=<oss>"
+PA_MODULE_USAGE("api=<oss> "
"subdevices=<init all subdevices>");
#endif
PA_MODULE_DEPRECATED("Please use module-udev-detect instead of module-hal-detect!");
diff --git a/src/modules/module-intended-roles.c b/src/modules/module-intended-roles.c
index 78a2c49c..d19444d2 100644
--- a/src/modules/module-intended-roles.c
+++ b/src/modules/module-intended-roles.c
@@ -447,7 +447,7 @@ fail:
if (ma)
pa_modargs_free(ma);
- return -1;
+ return -1;
}
void pa__done(pa_module*m) {
diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c
index 88df67ec..f6430f29 100644
--- a/src/modules/module-ladspa-sink.c
+++ b/src/modules/module-ladspa-sink.c
@@ -50,19 +50,24 @@ PA_MODULE_DESCRIPTION(_("Virtual LADSPA sink"));
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
- _("sink_name=<name for the sink> "
- "sink_properties=<properties for the sink> "
- "master=<name of sink to filter> "
- "format=<sample format> "
- "rate=<sample rate> "
- "channels=<number of channels> "
- "channel_map=<channel map> "
- "plugin=<ladspa plugin name> "
- "label=<ladspa plugin label> "
- "control=<comma seperated list of input control values>"));
+ _("sink_name=<name for the sink> "
+ "sink_properties=<properties for the sink> "
+ "master=<name of sink to filter> "
+ "format=<sample format> "
+ "rate=<sample rate> "
+ "channels=<number of channels> "
+ "channel_map=<input channel map> "
+ "plugin=<ladspa plugin name> "
+ "label=<ladspa plugin label> "
+ "control=<comma seperated list of input control values> "
+ "input_ladspaport_map=<comma separated list of input LADSPA port names> "
+ "output_ladspaport_map=<comma separated list of output LADSPA port names> "));
#define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
+/* PLEASE NOTICE: The PortAudio ports and the LADSPA ports are two different concepts.
+They are not related and where possible the names of the LADSPA port variables contains "ladspa" to avoid confusion */
+
struct userdata {
pa_module *module;
@@ -70,15 +75,14 @@ struct userdata {
pa_sink_input *sink_input;
const LADSPA_Descriptor *descriptor;
- unsigned channels;
LADSPA_Handle handle[PA_CHANNELS_MAX];
- LADSPA_Data *input, *output;
+ unsigned long max_ladspaport_count, input_count, output_count, channels;
+ LADSPA_Data **input, **output;
size_t block_size;
- unsigned long input_port, output_port;
LADSPA_Data *control;
/* This is a dummy buffer. Every port must be connected, but we don't care
- about control out ports. We connect them all to this single buffer. */
+ about control out ports. We connect them all to this single buffer. */
LADSPA_Data control_out;
pa_memblockq *memblockq;
@@ -97,6 +101,8 @@ static const char* const valid_modargs[] = {
"plugin",
"label",
"control",
+ "input_ladspaport_map",
+ "output_ladspaport_map",
NULL
};
@@ -106,26 +112,26 @@ static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t of
switch (code) {
- case PA_SINK_MESSAGE_GET_LATENCY:
+ case PA_SINK_MESSAGE_GET_LATENCY:
- /* The sink is _put() before the sink input is, so let's
- * make sure we don't access it in that time. Also, the
- * sink input is first shut down, the sink second. */
- if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
+ /* The sink is _put() before the sink input is, so let's
+ * make sure we don't access it in that time. Also, the
+ * sink input is first shut down, the sink second. */
+ if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
!PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) {
- *((pa_usec_t*) data) = 0;
- return 0;
- }
+ *((pa_usec_t*) data) = 0;
+ return 0;
+ }
- *((pa_usec_t*) data) =
+ *((pa_usec_t*) data) =
- /* Get the latency of the master sink */
- pa_sink_get_latency_within_thread(u->sink_input->sink) +
+ /* Get the latency of the master sink */
+ pa_sink_get_latency_within_thread(u->sink_input->sink) +
- /* Add the latency internal to our sink input on top */
- pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec);
+ /* Add the latency internal to our sink input on top */
+ pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec);
- return 0;
+ return 0;
}
return pa_sink_process_msg(o, code, data, offset, chunk);
@@ -139,7 +145,7 @@ static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
pa_assert_se(u = s->userdata);
if (!PA_SINK_IS_LINKED(state) ||
- !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+ !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
return 0;
pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED);
@@ -154,7 +160,7 @@ static void sink_request_rewind_cb(pa_sink *s) {
pa_assert_se(u = s->userdata);
if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
- !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+ !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
return;
/* Just hand this one over to the master sink */
@@ -171,13 +177,13 @@ static void sink_update_requested_latency_cb(pa_sink *s) {
pa_assert_se(u = s->userdata);
if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
- !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+ !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
return;
/* Just hand this one over to the master sink */
pa_sink_input_set_requested_latency_within_thread(
- u->sink_input,
- pa_sink_get_requested_latency_within_thread(s));
+ u->sink_input,
+ pa_sink_get_requested_latency_within_thread(s));
}
/* Called from main context */
@@ -188,7 +194,7 @@ static void sink_set_volume_cb(pa_sink *s) {
pa_assert_se(u = s->userdata);
if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
- !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+ !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
return;
pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, TRUE);
@@ -202,7 +208,7 @@ static void sink_set_mute_cb(pa_sink *s) {
pa_assert_se(u = s->userdata);
if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
- !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+ !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
return;
pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
@@ -213,7 +219,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
struct userdata *u;
float *src, *dst;
size_t fs;
- unsigned n, c;
+ unsigned n, h, c;
pa_memchunk tchunk;
pa_sink_input_assert_ref(i);
@@ -248,10 +254,12 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
src = (float*) ((uint8_t*) pa_memblock_acquire(tchunk.memblock) + tchunk.index);
dst = (float*) pa_memblock_acquire(chunk->memblock);
- for (c = 0; c < u->channels; c++) {
- pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input, sizeof(float), src+c, u->channels*sizeof(float), n);
- u->descriptor->run(u->handle[c], n);
- pa_sample_clamp(PA_SAMPLE_FLOAT32NE, dst+c, u->channels*sizeof(float), u->output, sizeof(float), n);
+ for (h = 0; h < (u->channels / u->max_ladspaport_count); h++) {
+ for (c = 0; c < u->input_count; c++)
+ pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input[c], sizeof(float), src+ h*u->max_ladspaport_count + c, u->channels*sizeof(float), n);
+ u->descriptor->run(u->handle[h], n);
+ for (c = 0; c < u->output_count; c++)
+ pa_sample_clamp(PA_SAMPLE_FLOAT32NE, dst + h*u->max_ladspaport_count + c, u->channels*sizeof(float), u->output[c], sizeof(float), n);
}
pa_memblock_release(tchunk.memblock);
@@ -286,10 +294,10 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
/* Reset the plugin */
if (u->descriptor->deactivate)
- for (c = 0; c < u->channels; c++)
+ for (c = 0; c < (u->channels / u->max_ladspaport_count); c++)
u->descriptor->deactivate(u->handle[c]);
if (u->descriptor->activate)
- for (c = 0; c < u->channels; c++)
+ for (c = 0; c < (u->channels / u->max_ladspaport_count); c++)
u->descriptor->activate(u->handle[c]);
}
}
@@ -399,7 +407,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
/* If we are added for the first time, ask for a rewinding so that
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
- i->thread_info.state == PA_SINK_INPUT_INIT) {
+ i->thread_info.state == PA_SINK_INPUT_INIT) {
pa_log_debug("Requesting rewind due to state change.");
pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
}
@@ -471,14 +479,13 @@ int pa__init(pa_module*m) {
pa_sink *master;
pa_sink_input_new_data sink_input_data;
pa_sink_new_data sink_data;
- const char *plugin, *label;
+ const char *plugin, *label, *input_ladspaport_map, *output_ladspaport_map;
LADSPA_Descriptor_Function descriptor_func;
+ unsigned long input_ladspaport[PA_CHANNELS_MAX], output_ladspaport[PA_CHANNELS_MAX];
const char *e, *cdata;
const LADSPA_Descriptor *d;
- unsigned long input_port, output_port, p, j, n_control;
- unsigned c;
+ unsigned long p, h, j, n_control, c;
pa_bool_t *use_default = NULL;
- pa_memchunk silence;
pa_assert(m);
@@ -512,15 +519,22 @@ int pa__init(pa_module*m) {
goto fail;
}
+ if (!(input_ladspaport_map = pa_modargs_get_value(ma, "input_ladspaport_map", NULL)))
+ pa_log_debug("Using default input ladspa port mapping");
+
+ if (!(output_ladspaport_map = pa_modargs_get_value(ma, "output_ladspaport_map", NULL)))
+ pa_log_debug("Using default output ladspa port mapping");
+
cdata = pa_modargs_get_value(ma, "control", NULL);
u = pa_xnew0(struct userdata, 1);
u->module = m;
m->userdata = u;
-
- pa_silence_memchunk_get(&m->core->silence_cache, m->core->mempool, &silence, &ss, 0);
- u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, &silence);
- pa_memblock_unref(silence.memblock);
+ u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
+ u->max_ladspaport_count = 1; /*to avoid division by zero etc. in pa__done when failing before this value has been set*/
+ u->channels = 0;
+ u->input = NULL;
+ u->output = NULL;
if (!(e = getenv("LADSPA_PATH")))
e = LADSPA_PATH;
@@ -562,64 +576,127 @@ int pa__init(pa_module*m) {
pa_log_debug("Maker: %s", d->Maker);
pa_log_debug("Copyright: %s", d->Copyright);
- input_port = output_port = (unsigned long) -1;
n_control = 0;
+ u->channels = ss.channels;
+ /*
+ * Enumerate ladspa ports
+ * Default mapping is in order given by the plugin
+ */
for (p = 0; p < d->PortCount; p++) {
+ if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
+ if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) {
+ pa_log_debug("Port %lu is input: %s", p, d->PortNames[p]);
+ input_ladspaport[u->input_count] = p;
+ u->input_count++;
+ } else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) {
+ pa_log_debug("Port %lu is output: %s", p, d->PortNames[p]);
+ output_ladspaport[u->output_count] = p;
+ u->output_count++;
+ }
+ } else if (LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]) && LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) {
+ pa_log_debug("Port %lu is control: %s", p, d->PortNames[p]);
+ n_control++;
+ } else
+ pa_log_debug("Ignored port %s", d->PortNames[p]);
+ /* XXX: Has anyone ever seen an in-place plugin with non-equal number of input and output ports? */
+ /* Could be if the plugin is for up-mixing stereo to 5.1 channels */
+ /* Or if the plugin is down-mixing 5.1 to two channel stereo or binaural encoded signal */
+ if (u->input_count > u->max_ladspaport_count)
+ u->max_ladspaport_count = u->input_count;
+ else
+ u->max_ladspaport_count = u->output_count;
+ }
+
+ if (u->channels % u->max_ladspaport_count) {
+ pa_log("Cannot handle non-integral number of plugins required for given number of channels");
+ goto fail;
+ }
- if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
+ pa_log_debug("Will run %lu plugin instances", u->channels / u->max_ladspaport_count);
- if (strcmp(d->PortNames[p], "Input") == 0) {
- pa_assert(input_port == (unsigned long) -1);
- input_port = p;
- } else {
- pa_log("Found audio input port on plugin we cannot handle: %s", d->PortNames[p]);
+ /* Parse data for input ladspa port map */
+ if (input_ladspaport_map) {
+ const char *state = NULL;
+ char *pname;
+ c = 0;
+ while ((pname = pa_split(input_ladspaport_map, ",", &state))) {
+ if (c == u->input_count) {
+ pa_log("Too many ports in input ladspa port map");
goto fail;
}
- } else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
- if (strcmp(d->PortNames[p], "Output") == 0) {
- pa_assert(output_port == (unsigned long) -1);
- output_port = p;
- } else {
- pa_log("Found audio output port on plugin we cannot handle: %s", d->PortNames[p]);
- goto fail;
+ for (p = 0; p < d->PortCount; p++) {
+ if (strcmp(d->PortNames[p], pname) == 0) {
+ if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p]) && LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) {
+ input_ladspaport[c] = p;
+ } else {
+ pa_log("Port %s is not an audio input ladspa port", pname);
+ pa_xfree(pname);
+ goto fail;
+ }
+ }
}
-
- } else if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]))
- n_control++;
- else {
- pa_assert(LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]));
- pa_log_debug("Ignored control output port \"%s\".", d->PortNames[p]);
+ c++;
+ pa_xfree(pname);
}
}
- if ((input_port == (unsigned long) -1) || (output_port == (unsigned long) -1)) {
- pa_log("Failed to identify input and output ports. "
- "Right now this module can only deal with plugins which provide an 'Input' and an 'Output' audio port. "
- "Patches welcome!");
- goto fail;
+ /* Parse data for output port map */
+ if (output_ladspaport_map) {
+ const char *state = NULL;
+ char *pname;
+ c = 0;
+ while ((pname = pa_split(output_ladspaport_map, ",", &state))) {
+ if (c == u->output_count) {
+ pa_log("Too many ports in output ladspa port map");
+ goto fail;
+ }
+ for (p = 0; p < d->PortCount; p++) {
+ if (strcmp(d->PortNames[p], pname) == 0) {
+ if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p]) && LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) {
+ output_ladspaport[c] = p;
+ } else {
+ pa_log("Port %s is not an output ladspa port", pname);
+ pa_xfree(pname);
+ goto fail;
+ }
+ }
+ }
+ c++;
+ pa_xfree(pname);
+ }
}
+
u->block_size = pa_frame_align(pa_mempool_block_size_max(m->core->mempool), &ss);
- u->input = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
- if (LADSPA_IS_INPLACE_BROKEN(d->Properties))
- u->output = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
- else
+ /* Create buffers */
+ if (LADSPA_IS_INPLACE_BROKEN(d->Properties)) {
+ u->input = (LADSPA_Data**) pa_xnew(LADSPA_Data*, (unsigned) u->input_count);
+ for (c = 0; c < u->input_count; c++)
+ u->input[c] = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
+ u->output = (LADSPA_Data**) pa_xnew(LADSPA_Data*, (unsigned) u->output_count);
+ for (c = 0; c < u->output_count; c++)
+ u->output[c] = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
+ } else {
+ u->input = (LADSPA_Data**) pa_xnew(LADSPA_Data*, (unsigned) u->max_ladspaport_count);
+ for (c = 0; c < u->max_ladspaport_count; c++)
+ u->input[c] = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
u->output = u->input;
-
- u->channels = ss.channels;
-
- for (c = 0; c < ss.channels; c++) {
- if (!(u->handle[c] = d->instantiate(d, ss.rate))) {
- pa_log("Failed to instantiate plugin %s with label %s for channel %i", plugin, d->Label, c);
+ }
+ /* Initialize plugin instances */
+ for (h = 0; h < (u->channels / u->max_ladspaport_count); h++) {
+ if (!(u->handle[h] = d->instantiate(d, ss.rate))) {
+ pa_log("Failed to instantiate plugin %s with label %s", plugin, d->Label);
goto fail;
}
- d->connect_port(u->handle[c], input_port, u->input);
- d->connect_port(u->handle[c], output_port, u->output);
+ for (c = 0; c < u->input_count; c++)
+ d->connect_port(u->handle[h], input_ladspaport[c], u->input[c]);
+ for (c = 0; c < u->output_count; c++)
+ d->connect_port(u->handle[h], output_ladspaport[c], u->output[c]);
}
if (!cdata && n_control > 0) {
@@ -630,7 +707,6 @@ int pa__init(pa_module*m) {
if (n_control > 0) {
const char *state = NULL;
char *k;
- unsigned long h;
u->control = pa_xnew(LADSPA_Data, (unsigned) n_control);
use_default = pa_xnew(pa_bool_t, (unsigned) n_control);
@@ -658,7 +734,7 @@ int pa__init(pa_module*m) {
}
/* The previous loop doesn't take the last control value into account
- if it is left empty, so we do it here. */
+ if it is left empty, so we do it here. */
if (*cdata == 0 || cdata[strlen(cdata) - 1] == ',') {
if (p < n_control)
use_default[p] = TRUE;
@@ -684,7 +760,7 @@ int pa__init(pa_module*m) {
continue;
if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) {
- for (c = 0; c < ss.channels; c++)
+ for (c = 0; c < (u->channels / u->max_ladspaport_count); c++)
d->connect_port(u->handle[c], p, &u->control_out);
continue;
}
@@ -709,53 +785,53 @@ int pa__init(pa_module*m) {
switch (hint & LADSPA_HINT_DEFAULT_MASK) {
- case LADSPA_HINT_DEFAULT_MINIMUM:
- u->control[h] = lower;
- break;
-
- case LADSPA_HINT_DEFAULT_MAXIMUM:
- u->control[h] = upper;
- break;
-
- case LADSPA_HINT_DEFAULT_LOW:
- if (LADSPA_IS_HINT_LOGARITHMIC(hint))
- u->control[h] = (LADSPA_Data) exp(log(lower) * 0.75 + log(upper) * 0.25);
- else
- u->control[h] = (LADSPA_Data) (lower * 0.75 + upper * 0.25);
- break;
-
- case LADSPA_HINT_DEFAULT_MIDDLE:
- if (LADSPA_IS_HINT_LOGARITHMIC(hint))
- u->control[h] = (LADSPA_Data) exp(log(lower) * 0.5 + log(upper) * 0.5);
- else
- u->control[h] = (LADSPA_Data) (lower * 0.5 + upper * 0.5);
- break;
-
- case LADSPA_HINT_DEFAULT_HIGH:
- if (LADSPA_IS_HINT_LOGARITHMIC(hint))
- u->control[h] = (LADSPA_Data) exp(log(lower) * 0.25 + log(upper) * 0.75);
- else
- u->control[h] = (LADSPA_Data) (lower * 0.25 + upper * 0.75);
- break;
-
- case LADSPA_HINT_DEFAULT_0:
- u->control[h] = 0;
- break;
-
- case LADSPA_HINT_DEFAULT_1:
- u->control[h] = 1;
- break;
-
- case LADSPA_HINT_DEFAULT_100:
- u->control[h] = 100;
- break;
-
- case LADSPA_HINT_DEFAULT_440:
- u->control[h] = 440;
- break;
-
- default:
- pa_assert_not_reached();
+ case LADSPA_HINT_DEFAULT_MINIMUM:
+ u->control[h] = lower;
+ break;
+
+ case LADSPA_HINT_DEFAULT_MAXIMUM:
+ u->control[h] = upper;
+ break;
+
+ case LADSPA_HINT_DEFAULT_LOW:
+ if (LADSPA_IS_HINT_LOGARITHMIC(hint))
+ u->control[h] = (LADSPA_Data) exp(log(lower) * 0.75 + log(upper) * 0.25);
+ else
+ u->control[h] = (LADSPA_Data) (lower * 0.75 + upper * 0.25);
+ break;
+
+ case LADSPA_HINT_DEFAULT_MIDDLE:
+ if (LADSPA_IS_HINT_LOGARITHMIC(hint))
+ u->control[h] = (LADSPA_Data) exp(log(lower) * 0.5 + log(upper) * 0.5);
+ else
+ u->control[h] = (LADSPA_Data) (lower * 0.5 + upper * 0.5);
+ break;
+
+ case LADSPA_HINT_DEFAULT_HIGH:
+ if (LADSPA_IS_HINT_LOGARITHMIC(hint))
+ u->control[h] = (LADSPA_Data) exp(log(lower) * 0.25 + log(upper) * 0.75);
+ else
+ u->control[h] = (LADSPA_Data) (lower * 0.25 + upper * 0.75);
+ break;
+
+ case LADSPA_HINT_DEFAULT_0:
+ u->control[h] = 0;
+ break;
+
+ case LADSPA_HINT_DEFAULT_1:
+ u->control[h] = 1;
+ break;
+
+ case LADSPA_HINT_DEFAULT_100:
+ u->control[h] = 100;
+ break;
+
+ case LADSPA_HINT_DEFAULT_440:
+ u->control[h] = 440;
+ break;
+
+ default:
+ pa_assert_not_reached();
}
}
@@ -764,7 +840,7 @@ int pa__init(pa_module*m) {
pa_log_debug("Binding %f to port %s", u->control[h], d->PortNames[p]);
- for (c = 0; c < ss.channels; c++)
+ for (c = 0; c < (u->channels / u->max_ladspaport_count); c++)
d->connect_port(u->handle[c], p, &u->control[h]);
h++;
@@ -774,7 +850,7 @@ int pa__init(pa_module*m) {
}
if (d->activate)
- for (c = 0; c < u->channels; c++)
+ for (c = 0; c < (u->channels / u->max_ladspaport_count); c++)
d->activate(u->handle[c]);
/* Create sink */
@@ -832,6 +908,7 @@ int pa__init(pa_module*m) {
sink_input_data.driver = __FILE__;
sink_input_data.module = m;
sink_input_data.sink = master;
+ sink_input_data.origin_sink = u->sink;
pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "LADSPA Stream");
pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
@@ -859,11 +936,12 @@ int pa__init(pa_module*m) {
u->sink_input->mute_changed = sink_input_mute_changed_cb;
u->sink_input->userdata = u;
+ u->sink->input_to_master = u->sink_input;
+
pa_sink_put(u->sink);
pa_sink_input_put(u->sink_input);
pa_modargs_free(ma);
-
pa_xfree(use_default);
return 0;
@@ -898,7 +976,7 @@ void pa__done(pa_module*m) {
return;
/* See comments in sink_input_kill_cb() above regarding
- * destruction order! */
+ * destruction order! */
if (u->sink_input)
pa_sink_input_unlink(u->sink_input);
@@ -912,21 +990,36 @@ void pa__done(pa_module*m) {
if (u->sink)
pa_sink_unref(u->sink);
- for (c = 0; c < u->channels; c++)
+ for (c = 0; c < (u->channels / u->max_ladspaport_count); c++) {
if (u->handle[c]) {
if (u->descriptor->deactivate)
u->descriptor->deactivate(u->handle[c]);
u->descriptor->cleanup(u->handle[c]);
}
+ }
- if (u->output != u->input)
- pa_xfree(u->output);
+ if (u->output == u->input) {
+ if (u->input != NULL) {
+ for (c = 0; c < u->max_ladspaport_count; c++)
+ pa_xfree(u->input[c]);
+ pa_xfree(u->input);
+ }
+ } else {
+ if (u->input != NULL) {
+ for (c = 0; c < u->input_count; c++)
+ pa_xfree(u->input[c]);
+ pa_xfree(u->input);
+ }
+ if (u->output != NULL) {
+ for (c = 0; c < u->output_count; c++)
+ pa_xfree(u->output[c]);
+ pa_xfree(u->output);
+ }
+ }
if (u->memblockq)
pa_memblockq_free(u->memblockq);
- pa_xfree(u->input);
pa_xfree(u->control);
-
pa_xfree(u);
}
diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 8cabf71b..9a8640b1 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -437,9 +437,9 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in
switch (code) {
case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
- pa_usec_t *r = data;
+ pa_usec_t *r = data;
- pa_sink_input_assert_io_context(u->sink_input);
+ pa_sink_input_assert_io_context(u->sink_input);
*r = pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &u->sink_input->sample_spec);
diff --git a/src/modules/module-match.c b/src/modules/module-match.c
index f9f36fdb..c8f27062 100644
--- a/src/modules/module-match.c
+++ b/src/modules/module-match.c
@@ -261,7 +261,7 @@ fail:
if (ma)
pa_modargs_free(ma);
- return -1;
+ return -1;
}
void pa__done(pa_module*m) {
diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c
index 4ed91aae..6623aef4 100644
--- a/src/modules/module-pipe-sink.c
+++ b/src/modules/module-pipe-sink.c
@@ -61,7 +61,7 @@ PA_MODULE_USAGE(
"sink_properties=<properties for the sink> "
"file=<path of the FIFO> "
"format=<sample format> "
- "rate=<sample rate>"
+ "rate=<sample rate> "
"channels=<number of channels> "
"channel_map=<channel map>");
@@ -362,7 +362,7 @@ void pa__done(pa_module*m) {
pa_sink_unref(u->sink);
if (u->memchunk.memblock)
- pa_memblock_unref(u->memchunk.memblock);
+ pa_memblock_unref(u->memchunk.memblock);
if (u->rtpoll_item)
pa_rtpoll_item_free(u->rtpoll_item);
diff --git a/src/modules/module-position-event-sounds.c b/src/modules/module-position-event-sounds.c
index ee4c8c88..3cba0f37 100644
--- a/src/modules/module-position-event-sounds.c
+++ b/src/modules/module-position-event-sounds.c
@@ -164,7 +164,7 @@ fail:
if (ma)
pa_modargs_free(ma);
- return -1;
+ return -1;
}
void pa__done(pa_module*m) {
diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c
index 52506f95..29cb419d 100644
--- a/src/modules/module-protocol-stub.c
+++ b/src/modules/module-protocol-stub.c
@@ -135,7 +135,7 @@
PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION);
PA_MODULE_USAGE("auth-anonymous=<don't check for cookies?> "
"auth-cookie=<path to cookie file> "
- "auth-cookie-enabled=<enable cookie authentification? "
+ "auth-cookie-enabled=<enable cookie authentification?> "
AUTH_USAGE
SOCKET_USAGE);
#elif defined(USE_PROTOCOL_ESOUND)
@@ -164,7 +164,7 @@
"source=<source to connect to> "
"auth-anonymous=<don't verify cookies?> "
"auth-cookie=<path to cookie file> "
- "auth-cookie-enabled=<enable cookie authentification? "
+ "auth-cookie-enabled=<enable cookie authentification?> "
AUTH_USAGE
SOCKET_USAGE);
#else
diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c
index 43748bd0..7f64f306 100644
--- a/src/modules/module-remap-sink.c
+++ b/src/modules/module-remap-sink.c
@@ -420,6 +420,7 @@ int pa__init(pa_module*m) {
sink_input_data.driver = __FILE__;
sink_input_data.module = m;
sink_input_data.sink = master;
+ sink_input_data.origin_sink = u->sink;
pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Remapped Stream");
pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
@@ -446,6 +447,8 @@ int pa__init(pa_module*m) {
u->sink_input->moving = sink_input_moving_cb;
u->sink_input->userdata = u;
+ u->sink->input_to_master = u->sink_input;
+
pa_sink_put(u->sink);
pa_sink_input_put(u->sink_input);
diff --git a/src/modules/module-rygel-media-server.c b/src/modules/module-rygel-media-server.c
index 76b485c3..9d23e8a4 100644
--- a/src/modules/module-rygel-media-server.c
+++ b/src/modules/module-rygel-media-server.c
@@ -723,10 +723,7 @@ static DBusHandlerResult root_handler(DBusConnection *c, DBusMessage *m, void *u
const char *xml = ROOT_INTROSPECT_XML;
pa_assert_se(r = dbus_message_new_method_return(m));
- pa_assert_se(dbus_message_append_args(
- r,
- DBUS_TYPE_STRING, &xml,
- DBUS_TYPE_INVALID));
+ pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
} else
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -938,10 +935,7 @@ static DBusHandlerResult sinks_and_sources_handler(DBusConnection *c, DBusMessag
xml = pa_strbuf_tostring_free(sb);
pa_assert_se(r = dbus_message_new_method_return(m));
- pa_assert_se(dbus_message_append_args(
- r,
- DBUS_TYPE_STRING, &xml,
- DBUS_TYPE_INVALID));
+ pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
pa_xfree(xml);
} else
@@ -1012,10 +1006,7 @@ static DBusHandlerResult sinks_and_sources_handler(DBusConnection *c, DBusMessag
ITEM_INTROSPECT_XML;
pa_assert_se(r = dbus_message_new_method_return(m));
- pa_assert_se(dbus_message_append_args(
- r,
- DBUS_TYPE_STRING, &xml,
- DBUS_TYPE_INVALID));
+ pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
} else
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c
index 396094ce..ee06b3be 100644
--- a/src/modules/module-solaris.c
+++ b/src/modules/module-solaris.c
@@ -307,8 +307,8 @@ static int auto_format(int fd, int mode, pa_sample_spec *ss) {
info.record.encoding = AUDIO_ENCODING_LINEAR;
break;
default:
- pa_log("AUDIO_SETINFO: Unsupported sample format.");
- return -1;
+ pa_log("AUDIO_SETINFO: Unsupported sample format.");
+ return -1;
}
}
@@ -1015,7 +1015,7 @@ int pa__init(pa_module *m) {
else
pa_log_warn("Could not register SIGPOLL handler");
- if (!(u->thread = pa_thread_new(thread_func, u))) {
+ if (!(u->thread = pa_thread_new("solaris", thread_func, u))) {
pa_log("Failed to create thread.");
goto fail;
}
diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
index f8fecd89..df48dce2 100644
--- a/src/modules/module-stream-restore.c
+++ b/src/modules/module-stream-restore.c
@@ -1168,6 +1168,8 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
}
if (sink_input->save_volume) {
+ pa_assert(pa_sink_input_is_volume_writable(sink_input));
+
entry.channel_map = sink_input->channel_map;
pa_sink_input_get_volume(sink_input, &entry.volume, FALSE);
entry.volume_valid = TRUE;
@@ -1327,8 +1329,11 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
if ((e = read_entry(u, name))) {
if (u->restore_volume && e->volume_valid) {
-
- if (!new_data->volume_is_set) {
+ if (!pa_sink_input_new_data_is_volume_writable(new_data))
+ pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name);
+ else if (new_data->volume_is_set)
+ pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
+ else {
pa_cvolume v;
pa_log_info("Restoring volume for sink input %s.", name);
@@ -1339,8 +1344,7 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
new_data->volume_is_absolute = FALSE;
new_data->save_volume = TRUE;
- } else
- pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
+ }
}
if (u->restore_muted && e->muted_valid) {
@@ -1615,7 +1619,7 @@ static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
}
pa_xfree(n);
- if (u->restore_volume && e->volume_valid) {
+ if (u->restore_volume && e->volume_valid && pa_sink_input_is_volume_writable(si)) {
pa_cvolume v;
v = e->volume;
@@ -2106,7 +2110,7 @@ fail:
if (ma)
pa_modargs_free(ma);
- return -1;
+ return -1;
}
#ifdef HAVE_DBUS
diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c
index cfb78792..2bc424b3 100644
--- a/src/modules/module-suspend-on-idle.c
+++ b/src/modules/module-suspend-on-idle.c
@@ -41,6 +41,7 @@ PA_MODULE_AUTHOR("Lennart Poettering");
PA_MODULE_DESCRIPTION("When a sink/source is idle for too long, suspend it");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(TRUE);
+PA_MODULE_USAGE("timeout=<timeout>");
static const char* const valid_modargs[] = {
"timeout",
diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c
index 176c2c00..af1bb955 100644
--- a/src/modules/module-tunnel.c
+++ b/src/modules/module-tunnel.c
@@ -379,7 +379,7 @@ static void command_stream_buffer_attr_changed(pa_pdispatch *pd, uint32_t comman
/* Called from main context */
static void command_started(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
- struct userdata *u = userdata;
+ struct userdata *u = userdata;
pa_assert(pd);
pa_assert(t);
@@ -393,7 +393,7 @@ static void command_started(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa
#endif
/* Called from IO thread context */
-static void check_smoother_status(struct userdata *u, pa_bool_t past) {
+static void check_smoother_status(struct userdata *u, pa_bool_t past) {
pa_usec_t x;
pa_assert(u);
@@ -973,8 +973,7 @@ static void server_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa
pa_tagstruct_gets(t, &default_sink_name) < 0 ||
pa_tagstruct_gets(t, &default_source_name) < 0 ||
pa_tagstruct_getu32(t, &cookie) < 0 ||
- (u->version >= 15 &&
- pa_tagstruct_get_channel_map(t, &cm) < 0)) {
+ (u->version >= 15 && pa_tagstruct_get_channel_map(t, &cm) < 0)) {
pa_log("Parse failure");
goto fail;
@@ -2037,7 +2036,7 @@ fail:
pa_xfree(dn);
- return -1;
+ return -1;
}
void pa__done(pa_module*m) {
diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c
index 1eaa84fd..63ad1952 100644
--- a/src/modules/module-udev-detect.c
+++ b/src/modules/module-udev-detect.c
@@ -442,8 +442,7 @@ static void process_device(struct userdata *u, struct udev_device *dev) {
if (action && pa_streq(action, "remove"))
remove_card(u, dev);
- else if ((!action || pa_streq(action, "change")) &&
- udev_device_get_property_value(dev, "SOUND_INITIALIZED"))
+ else if ((!action || pa_streq(action, "change")) && udev_device_get_property_value(dev, "SOUND_INITIALIZED"))
card_changed(u, dev);
/* For an explanation why we don't look for 'add' events here
diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c
index fac204d4..cc134900 100644
--- a/src/modules/module-virtual-sink.c
+++ b/src/modules/module-virtual-sink.c
@@ -57,6 +57,8 @@ PA_MODULE_USAGE(
"rate=<sample rate> "
"channels=<number of channels> "
"channel_map=<channel map> "
+ "use_volume_sharing=<yes or no> "
+ "force_flat_volume=<yes or no> "
));
#define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
@@ -81,6 +83,8 @@ static const char* const valid_modargs[] = {
"rate",
"channels",
"channel_map",
+ "use_volume_sharing",
+ "force_flat_volume",
NULL
};
@@ -477,7 +481,9 @@ int pa__init(pa_module*m) {
pa_sink *master=NULL;
pa_sink_input_new_data sink_input_data;
pa_sink_new_data sink_data;
- pa_bool_t *use_default = NULL;
+ pa_bool_t use_volume_sharing = FALSE;
+ pa_bool_t force_flat_volume = FALSE;
+ pa_memchunk silence;
pa_assert(m);
@@ -501,6 +507,21 @@ int pa__init(pa_module*m) {
goto fail;
}
+ if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) {
+ pa_log("use_volume_sharing= expects a boolean argument");
+ goto fail;
+ }
+
+ if (pa_modargs_get_value_boolean(ma, "force_flat_volume", &force_flat_volume) < 0) {
+ pa_log("force_flat_volume= expects a boolean argument");
+ goto fail;
+ }
+
+ if (use_volume_sharing && force_flat_volume) {
+ pa_log("Flat volume can't be forced when using volume sharing.");
+ goto fail;
+ }
+
u = pa_xnew0(struct userdata, 1);
u->module = m;
m->userdata = u;
@@ -531,9 +552,9 @@ int pa__init(pa_module*m) {
pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Sink %s on %s", sink_data.name, z ? z : master->name);
}
- u->sink = pa_sink_new(m->core, &sink_data,
- PA_SINK_HW_MUTE_CTRL|PA_SINK_HW_VOLUME_CTRL|PA_SINK_DECIBEL_VOLUME|
- (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY)));
+ u->sink = pa_sink_new(m->core, &sink_data, (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))
+ | (use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0)
+ | (force_flat_volume ? PA_SINK_FLAT_VOLUME : 0));
pa_sink_new_data_done(&sink_data);
if (!u->sink) {
@@ -545,7 +566,7 @@ int pa__init(pa_module*m) {
u->sink->set_state = sink_set_state_cb;
u->sink->update_requested_latency = sink_update_requested_latency_cb;
u->sink->request_rewind = sink_request_rewind_cb;
- u->sink->set_volume = sink_set_volume_cb;
+ u->sink->set_volume = use_volume_sharing ? NULL : sink_set_volume_cb;
u->sink->set_mute = sink_set_mute_cb;
u->sink->userdata = u;
@@ -556,7 +577,8 @@ int pa__init(pa_module*m) {
sink_input_data.driver = __FILE__;
sink_input_data.module = m;
sink_input_data.sink = master;
- pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Sink Stream");
+ sink_input_data.origin_sink = u->sink;
+ pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Sink Stream from %s", pa_proplist_gets(u->sink->proplist, PA_PROP_DEVICE_DESCRIPTION));
pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
@@ -579,32 +601,29 @@ int pa__init(pa_module*m) {
u->sink_input->state_change = sink_input_state_change_cb;
u->sink_input->may_move_to = sink_input_may_move_to_cb;
u->sink_input->moving = sink_input_moving_cb;
- u->sink_input->volume_changed = sink_input_volume_changed_cb;
+ u->sink_input->volume_changed = use_volume_sharing ? NULL : sink_input_volume_changed_cb;
u->sink_input->mute_changed = sink_input_mute_changed_cb;
u->sink_input->userdata = u;
- /* (9) IF YOU REQUIRE A FIXED BLOCK SIZE MAKE SURE TO PASS A
- * SILENCE MEMBLOCK AS LAST PARAMETER
- * HERE. pa_sink_input_get_silence() IS USEFUL HERE. */
- u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
+ u->sink->input_to_master = u->sink_input;
- /* (10) INITIALIZE ANYTHING ELSE YOU NEED HERE */
+ pa_sink_input_get_silence(u->sink_input, &silence);
+ u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, &silence);
+ pa_memblock_unref(silence.memblock);
+
+ /* (9) INITIALIZE ANYTHING ELSE YOU NEED HERE */
pa_sink_put(u->sink);
pa_sink_input_put(u->sink_input);
pa_modargs_free(ma);
- pa_xfree(use_default);
-
return 0;
- fail:
+fail:
if (ma)
pa_modargs_free(ma);
- pa_xfree(use_default);
-
pa__done(m);
return -1;
diff --git a/src/modules/module-virtual-source.c b/src/modules/module-virtual-source.c
index fdf89b02..b8f2ab06 100644
--- a/src/modules/module-virtual-source.c
+++ b/src/modules/module-virtual-source.c
@@ -535,7 +535,6 @@ int pa__init(pa_module*m) {
pa_source *master=NULL;
pa_source_output_new_data source_output_data;
pa_source_new_data source_data;
- pa_bool_t *use_default = NULL;
/* optional for uplink_sink */
pa_sink_new_data sink_data;
@@ -629,10 +628,11 @@ int pa__init(pa_module*m) {
source_output_data.driver = __FILE__;
source_output_data.module = m;
source_output_data.source = master;
+ source_output_data.destination_source = u->source;
/* FIXME
source_output_data.flags = PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND; */
- pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Source Stream");
+ pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Source Stream of %s", pa_proplist_gets(u->source->proplist, PA_PROP_DEVICE_DESCRIPTION));
pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
pa_source_output_new_data_set_channel_map(&source_output_data, &map);
@@ -654,6 +654,8 @@ int pa__init(pa_module*m) {
u->source_output->moving = source_output_moving_cb;
u->source_output->userdata = u;
+ u->source->output_from_master = u->source_output;
+
pa_source_put(u->source);
pa_source_output_put(u->source_output);
@@ -711,16 +713,12 @@ int pa__init(pa_module*m) {
pa_modargs_free(ma);
- pa_xfree(use_default);
-
return 0;
- fail:
+fail:
if (ma)
pa_modargs_free(ma);
- pa_xfree(use_default);
-
pa__done(m);
return -1;
@@ -765,7 +763,7 @@ void pa__done(pa_module*m) {
pa_memblockq_free(u->memblockq);
if (u->sink_memblockq)
- pa_memblockq_free(u->sink_memblockq);
+ pa_memblockq_free(u->sink_memblockq);
pa_xfree(u);
}
diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c
index 6e484eae..a344c5eb 100644
--- a/src/modules/module-volume-restore.c
+++ b/src/modules/module-volume-restore.c
@@ -81,5 +81,5 @@ fail:
if (ma)
pa_modargs_free(ma);
- return -1;
+ return -1;
}
diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c
index 6c969212..9f119c59 100644
--- a/src/modules/module-waveout.c
+++ b/src/modules/module-waveout.c
@@ -56,11 +56,11 @@ PA_MODULE_USAGE(
"record=<enable source?> "
"playback=<enable sink?> "
"format=<sample format> "
- "channels=<number of channels> "
"rate=<sample rate> "
+ "channels=<number of channels> "
+ "channel_map=<channel map> "
"fragments=<number of fragments> "
- "fragment_size=<fragment size> "
- "channel_map=<channel map>");
+ "fragment_size=<fragment size>");
#define DEFAULT_SINK_NAME "wave_output"
#define DEFAULT_SOURCE_NAME "wave_input"
diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c
index c9dc4e7a..84dbbdaf 100644
--- a/src/modules/oss/module-oss.c
+++ b/src/modules/oss/module-oss.c
@@ -169,7 +169,7 @@ static void trigger(struct userdata *u, pa_bool_t quick) {
if (u->fd < 0)
return;
- pa_log_debug("trigger");
+ pa_log_debug("trigger");
if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state))
enable_bits |= PCM_ENABLE_INPUT;
diff --git a/src/modules/raop/base64.c b/src/modules/raop/base64.c
index 5b061034..37e47628 100644
--- a/src/modules/raop/base64.c
+++ b/src/modules/raop/base64.c
@@ -38,8 +38,7 @@
static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static int pos(char c)
-{
+static int pos(char c) {
if (c >= 'A' && c <= 'Z') return c - 'A' + 0;
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
if (c >= '0' && c <= '9') return c - '0' + 52;
@@ -48,8 +47,7 @@ static int pos(char c)
return -1;
}
-int pa_base64_encode(const void *data, int size, char **str)
-{
+int pa_base64_encode(const void *data, int size, char **str) {
char *s, *p;
int i;
int c;
@@ -84,8 +82,7 @@ int pa_base64_encode(const void *data, int size, char **str)
#define DECODE_ERROR 0xffffffff
-static unsigned int token_decode(const char *token)
-{
+static unsigned int token_decode(const char *token) {
int i;
unsigned int val = 0;
int marker = 0;
@@ -109,8 +106,7 @@ static unsigned int token_decode(const char *token)
return (marker << 24) | val;
}
-int pa_base64_decode(const char *str, void *data)
-{
+int pa_base64_decode(const char *str, void *data) {
const char *p;
unsigned char *q;
diff --git a/src/modules/raop/raop_client.c b/src/modules/raop/raop_client.c
index 7dd96839..05c7b169 100644
--- a/src/modules/raop/raop_client.c
+++ b/src/modules/raop/raop_client.c
@@ -173,8 +173,7 @@ static int rsa_encrypt(uint8_t *text, int len, uint8_t *res) {
return size;
}
-static int aes_encrypt(pa_raop_client* c, uint8_t *data, int size)
-{
+static int aes_encrypt(pa_raop_client* c, uint8_t *data, int size) {
uint8_t *buf;
int i=0, j;
@@ -193,8 +192,7 @@ static int aes_encrypt(pa_raop_client* c, uint8_t *data, int size)
return i;
}
-static inline void rtrimchar(char *str, char rc)
-{
+static inline void rtrimchar(char *str, char rc) {
char *sp = str + strlen(str) - 1;
while (sp >= str && *sp == rc) {
*sp = '\0';
@@ -231,8 +229,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata
c->callback(c->fd, c->userdata);
}
-static void rtsp_cb(pa_rtsp_client *rtsp, pa_rtsp_state state, pa_headerlist* headers, void *userdata)
-{
+static void rtsp_cb(pa_rtsp_client *rtsp, pa_rtsp_state state, pa_headerlist* headers, void *userdata) {
pa_raop_client* c = userdata;
pa_assert(c);
pa_assert(rtsp);
@@ -367,8 +364,7 @@ static void rtsp_cb(pa_rtsp_client *rtsp, pa_rtsp_state state, pa_headerlist* he
}
}
-pa_raop_client* pa_raop_client_new(pa_core *core, const char* host)
-{
+pa_raop_client* pa_raop_client_new(pa_core *core, const char* host) {
pa_raop_client* c = pa_xnew0(pa_raop_client, 1);
pa_assert(core);
@@ -386,8 +382,7 @@ pa_raop_client* pa_raop_client_new(pa_core *core, const char* host)
}
-void pa_raop_client_free(pa_raop_client* c)
-{
+void pa_raop_client_free(pa_raop_client* c) {
pa_assert(c);
if (c->rtsp)
@@ -397,8 +392,7 @@ void pa_raop_client_free(pa_raop_client* c)
}
-int pa_raop_connect(pa_raop_client* c)
-{
+int pa_raop_connect(pa_raop_client* c) {
char *sci;
struct {
uint32_t a;
@@ -432,8 +426,7 @@ int pa_raop_connect(pa_raop_client* c)
}
-int pa_raop_flush(pa_raop_client* c)
-{
+int pa_raop_flush(pa_raop_client* c) {
pa_assert(c);
pa_rtsp_flush(c->rtsp, c->seq, c->rtptime);
@@ -441,8 +434,7 @@ int pa_raop_flush(pa_raop_client* c)
}
-int pa_raop_client_set_volume(pa_raop_client* c, pa_volume_t volume)
-{
+int pa_raop_client_set_volume(pa_raop_client* c, pa_volume_t volume) {
int rv;
double db;
char *param;
@@ -464,8 +456,7 @@ int pa_raop_client_set_volume(pa_raop_client* c, pa_volume_t volume)
}
-int pa_raop_client_encode_sample(pa_raop_client* c, pa_memchunk* raw, pa_memchunk* encoded)
-{
+int pa_raop_client_encode_sample(pa_raop_client* c, pa_memchunk* raw, pa_memchunk* encoded) {
uint16_t len;
size_t bufmax;
uint8_t *bp, bpos;
@@ -547,16 +538,14 @@ int pa_raop_client_encode_sample(pa_raop_client* c, pa_memchunk* raw, pa_memchun
}
-void pa_raop_client_set_callback(pa_raop_client* c, pa_raop_client_cb_t callback, void *userdata)
-{
+void pa_raop_client_set_callback(pa_raop_client* c, pa_raop_client_cb_t callback, void *userdata) {
pa_assert(c);
c->callback = callback;
c->userdata = userdata;
}
-void pa_raop_client_set_closed_callback(pa_raop_client* c, pa_raop_client_closed_cb_t callback, void *userdata)
-{
+void pa_raop_client_set_closed_callback(pa_raop_client* c, pa_raop_client_closed_cb_t callback, void *userdata) {
pa_assert(c);
c->closed_callback = callback;
diff --git a/src/modules/rtp/rtp.h b/src/modules/rtp/rtp.h
index b197e82f..e975e750 100644
--- a/src/modules/rtp/rtp.h
+++ b/src/modules/rtp/rtp.h
@@ -40,6 +40,9 @@ typedef struct pa_rtp_context {
} pa_rtp_context;
pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload, size_t frame_size);
+
+/* If the memblockq doesn't have a silence memchunk set, then the caller must
+ * guarantee that the current read index doesn't point to a hole. */
int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q);
pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size);
diff --git a/src/modules/rtp/rtsp_client.c b/src/modules/rtp/rtsp_client.c
index fd3b1de3..8a5a1d75 100644
--- a/src/modules/rtp/rtsp_client.c
+++ b/src/modules/rtp/rtsp_client.c
@@ -372,8 +372,7 @@ void pa_rtsp_set_url(pa_rtsp_client* c, const char* url) {
c->url = pa_xstrdup(url);
}
-void pa_rtsp_add_header(pa_rtsp_client *c, const char* key, const char* value)
-{
+void pa_rtsp_add_header(pa_rtsp_client *c, const char* key, const char* value) {
pa_assert(c);
pa_assert(key);
pa_assert(value);
@@ -381,8 +380,7 @@ void pa_rtsp_add_header(pa_rtsp_client *c, const char* key, const char* value)
pa_headerlist_puts(c->headers, key, value);
}
-void pa_rtsp_remove_header(pa_rtsp_client *c, const char* key)
-{
+void pa_rtsp_remove_header(pa_rtsp_client *c, const char* key) {
pa_assert(c);
pa_assert(key);
diff --git a/src/modules/udev-util.c b/src/modules/udev-util.c
index 52df1039..356f7736 100644
--- a/src/modules/udev-util.c
+++ b/src/modules/udev-util.c
@@ -74,7 +74,7 @@ static int dehex(char x) {
static void proplist_sets_unescape(pa_proplist *p, const char *prop, const char *s) {
const char *f;
char *t, *r;
- int c;
+ int c = 0;
enum {
TEXT,
diff --git a/src/pulse/browser.c b/src/pulse/browser.c
index 4cf5d0c3..d0592284 100644
--- a/src/pulse/browser.c
+++ b/src/pulse/browser.c
@@ -20,7 +20,7 @@
***/
#ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
#endif
#include <string.h>
diff --git a/src/pulse/context.c b/src/pulse/context.c
index 8f632b5d..1480af53 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -53,6 +53,11 @@
#include <pulse/i18n.h>
#include <pulse/mainloop.h>
#include <pulse/timeval.h>
+#include <pulse/fork-detect.h>
+#include <pulse/client-conf.h>
+#ifdef HAVE_X11
+#include <pulse/client-conf-x11.h>
+#endif
#include <pulsecore/core-error.h>
#include <pulsecore/native-common.h>
@@ -71,14 +76,6 @@
#include <pulsecore/proplist-util.h>
#include "internal.h"
-
-#include "client-conf.h"
-#include "fork-detect.h"
-
-#ifdef HAVE_X11
-#include "client-conf-x11.h"
-#endif
-
#include "context.h"
void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
diff --git a/src/pulse/def.h b/src/pulse/def.h
index ac4ae538..a3b86223 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -748,6 +748,16 @@ typedef enum pa_sink_flags {
/**< The HW volume changes are syncronized with SW volume.
* \since 1.0 */
+/** \cond fulldocs */
+ /* PRIVATE: Server-side values -- do not try to use these at client-side.
+ * The server will filter out these flags anyway, so you should never see
+ * these flags in sinks. */
+
+ PA_SINK_SHARE_VOLUME_WITH_MASTER = 0x0400U,
+ /**< This sink shares the volume with the master sink (used by some filter
+ * sinks). */
+/** \endcond */
+
} pa_sink_flags_t;
/** \cond fulldocs */
@@ -761,6 +771,7 @@ typedef enum pa_sink_flags {
#define PA_SINK_DYNAMIC_LATENCY PA_SINK_DYNAMIC_LATENCY
#define PA_SINK_PASSTHROUGH PA_SINK_PASSTHROUGH
#define PA_SINK_SYNC_VOLUME PA_SINK_SYNC_VOLUME
+#define PA_SINK_SHARE_VOLUME_WITH_MASTER PA_SINK_SHARE_VOLUME_WITH_MASTER
/** \endcond */
diff --git a/src/pulse/ext-device-manager.c b/src/pulse/ext-device-manager.c
index 57cb57c8..7b78c24e 100644
--- a/src/pulse/ext-device-manager.c
+++ b/src/pulse/ext-device-manager.c
@@ -27,14 +27,13 @@
#include <pulse/context.h>
#include <pulse/gccmacro.h>
#include <pulse/xmalloc.h>
+#include <pulse/fork-detect.h>
+#include <pulse/operation.h>
#include <pulsecore/macro.h>
#include <pulsecore/pstream-util.h>
#include "internal.h"
-#include "operation.h"
-#include "fork-detect.h"
-
#include "ext-device-manager.h"
enum {
diff --git a/src/pulse/ext-stream-restore.c b/src/pulse/ext-stream-restore.c
index 10e9fd5d..7bc1a612 100644
--- a/src/pulse/ext-stream-restore.c
+++ b/src/pulse/ext-stream-restore.c
@@ -25,14 +25,13 @@
#include <pulse/context.h>
#include <pulse/gccmacro.h>
+#include <pulse/fork-detect.h>
+#include <pulse/operation.h>
#include <pulsecore/macro.h>
#include <pulsecore/pstream-util.h>
#include "internal.h"
-#include "operation.h"
-#include "fork-detect.h"
-
#include "ext-stream-restore.h"
enum {
diff --git a/src/pulse/glib-mainloop.c b/src/pulse/glib-mainloop.c
index 6afb7a2d..2e5f2f92 100644
--- a/src/pulse/glib-mainloop.c
+++ b/src/pulse/glib-mainloop.c
@@ -34,7 +34,7 @@
#include <glib.h>
#include "glib-mainloop.h"
-struct pa_io_event {
+struct pa_io_event {
pa_glib_mainloop *mainloop;
int dead;
@@ -336,7 +336,7 @@ static void glib_time_restart(pa_time_event*e, const struct timeval *tv) {
e->mainloop->cached_next_time_event = e;
} else if (e->mainloop->cached_next_time_event == e)
e->mainloop->cached_next_time_event = NULL;
- }
+}
static void glib_time_free(pa_time_event *e) {
g_assert(e);
diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
index 2a817881..ec27b928 100644
--- a/src/pulse/introspect.c
+++ b/src/pulse/introspect.c
@@ -29,14 +29,13 @@
#include <pulse/context.h>
#include <pulse/gccmacro.h>
#include <pulse/xmalloc.h>
+#include <pulse/fork-detect.h>
#include <pulsecore/macro.h>
#include <pulsecore/core-util.h>
#include <pulsecore/pstream-util.h>
#include "internal.h"
-#include "fork-detect.h"
-
#include "introspect.h"
/*** Statistics ***/
@@ -996,7 +995,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm
while (!pa_tagstruct_eof(t)) {
pa_sink_input_info i;
- pa_bool_t mute = FALSE, corked = FALSE;
+ pa_bool_t mute = FALSE, corked = FALSE, has_volume = FALSE, read_only_volume = FALSE;
pa_zero(i);
i.proplist = pa_proplist_new();
@@ -1015,7 +1014,9 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm
pa_tagstruct_gets(t, &i.driver) < 0 ||
(o->context->version >= 11 && pa_tagstruct_get_boolean(t, &mute) < 0) ||
(o->context->version >= 13 && pa_tagstruct_get_proplist(t, i.proplist) < 0) ||
- (o->context->version >= 19 && pa_tagstruct_get_boolean(t, &corked) < 0)) {
+ (o->context->version >= 19 && pa_tagstruct_get_boolean(t, &corked) < 0) ||
+ (o->context->version >= 20 && (pa_tagstruct_get_boolean(t, &has_volume) < 0 ||
+ pa_tagstruct_get_boolean(t, &read_only_volume) < 0))) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
pa_proplist_free(i.proplist);
@@ -1024,6 +1025,8 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm
i.mute = (int) mute;
i.corked = (int) corked;
+ i.has_volume = (int) has_volume;
+ i.read_only_volume = (int) read_only_volume;
if (o->callback) {
pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback;
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index bc50611e..1cadee52 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -503,6 +503,8 @@ typedef struct pa_sink_input_info {
int mute; /**< Stream muted \since 0.9.7 */
pa_proplist *proplist; /**< Property list \since 0.9.11 */
int corked; /**< Stream corked \since 1.0 */
+ int has_volume; /**< Stream has volume. If not set, then the meaning of this struct's volume member is unspecified. \since 1.0 */
+ int read_only_volume; /**< Stream volume can only be read. Although volume control is disabled, the stream volume is still not necessarily constant. \since 1.0 */
} pa_sink_input_info;
/** Callback prototype for pa_context_get_sink_input_info() and friends*/
diff --git a/src/pulse/mainloop-api.h b/src/pulse/mainloop-api.h
index 0ce2219b..212ff3cc 100644
--- a/src/pulse/mainloop-api.h
+++ b/src/pulse/mainloop-api.h
@@ -80,7 +80,7 @@ typedef void (*pa_defer_event_cb_t)(pa_mainloop_api*a, pa_defer_event* e, void *
typedef void (*pa_defer_event_destroy_cb_t)(pa_mainloop_api*a, pa_defer_event *e, void *userdata);
/** An abstract mainloop API vtable */
-struct pa_mainloop_api {
+struct pa_mainloop_api {
/** A pointer to some private, arbitrary data of the main loop implementation */
void *userdata;
diff --git a/src/pulse/scache.c b/src/pulse/scache.c
index cb8d7c59..6ed80a68 100644
--- a/src/pulse/scache.c
+++ b/src/pulse/scache.c
@@ -28,14 +28,14 @@
#include <string.h>
#include <pulse/utf8.h>
-#include <pulse/scache.h>
+#include <pulse/fork-detect.h>
#include <pulsecore/pstream-util.h>
#include <pulsecore/macro.h>
#include <pulsecore/proplist-util.h>
-#include "fork-detect.h"
#include "internal.h"
+#include "scache.h"
int pa_stream_connect_upload(pa_stream *s, size_t length) {
pa_tagstruct *t;
diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index addc36ae..aac18a31 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -29,10 +29,10 @@
#include <string.h>
#include <pulse/def.h>
-#include <pulse/stream.h>
#include <pulse/timeval.h>
#include <pulse/rtclock.h>
#include <pulse/xmalloc.h>
+#include <pulse/fork-detect.h>
#include <pulsecore/pstream-util.h>
#include <pulsecore/log.h>
@@ -41,8 +41,8 @@
#include <pulsecore/core-rtclock.h>
#include <pulsecore/core-util.h>
-#include "fork-detect.h"
#include "internal.h"
+#include "stream.h"
#define AUTO_TIMING_INTERVAL_START_USEC (10*PA_USEC_PER_MSEC)
#define AUTO_TIMING_INTERVAL_END_USEC (1500*PA_USEC_PER_MSEC)
@@ -790,7 +790,7 @@ void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32
s->underflow_callback(s, s->underflow_userdata);
}
- finish:
+finish:
pa_context_unref(c);
}
@@ -925,7 +925,7 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag,
if (pa_tagstruct_getu32(t, &s->channel) < 0 ||
s->channel == PA_INVALID_INDEX ||
- ((s->direction != PA_STREAM_UPLOAD) && (pa_tagstruct_getu32(t, &s->stream_index) < 0 || s->stream_index == PA_INVALID_INDEX)) ||
+ ((s->direction != PA_STREAM_UPLOAD) && (pa_tagstruct_getu32(t, &s->stream_index) < 0 || s->stream_index == PA_INVALID_INDEX)) ||
((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &requested_bytes) < 0)) {
pa_context_fail(s->context, PA_ERR_PROTOCOL);
goto finish;
diff --git a/src/pulse/subscribe.c b/src/pulse/subscribe.c
index 203bc928..52d0af35 100644
--- a/src/pulse/subscribe.c
+++ b/src/pulse/subscribe.c
@@ -31,7 +31,6 @@
#include <pulsecore/pstream-util.h>
#include "internal.h"
-
#include "subscribe.h"
void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
diff --git a/src/pulse/volume.c b/src/pulse/volume.c
index f74d7202..134c007d 100644
--- a/src/pulse/volume.c
+++ b/src/pulse/volume.c
@@ -263,7 +263,7 @@ pa_volume_t pa_sw_volume_from_linear(double v) {
* same volume value! That's why we need the lround() below!
*/
- return (pa_volume_t) PA_CLAMP_VOLUME(lround(cbrt(v) * PA_VOLUME_NORM));
+ return (pa_volume_t) PA_CLAMP_VOLUME((uint64_t) lround(cbrt(v) * PA_VOLUME_NORM));
}
double pa_sw_volume_to_linear(pa_volume_t v) {
@@ -375,8 +375,7 @@ char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) {
}
f = pa_sw_volume_to_dB(v);
- pa_snprintf(s, l, "%0.2f dB",
- isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
+ pa_snprintf(s, l, "%0.2f dB", isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
return s;
}
@@ -657,9 +656,9 @@ pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, flo
m = PA_MAX(left, right);
if (new_balance <= 0) {
- nright = (new_balance + 1.0f) * m;
+ nright = (new_balance + 1.0f) * m;
nleft = m;
- } else {
+ } else {
nleft = (1.0f - new_balance) * m;
nright = m;
}
@@ -720,7 +719,7 @@ pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map
return pa_cvolume_set(v, v->channels, max);
for (c = 0; c < v->channels; c++)
- v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
+ v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
return v;
}
@@ -798,9 +797,9 @@ pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float
m = PA_MAX(front, rear);
if (new_fade <= 0) {
- nfront = (new_fade + 1.0f) * m;
+ nfront = (new_fade + 1.0f) * m;
nrear = m;
- } else {
+ } else {
nrear = (1.0f - new_fade) * m;
nfront = m;
}
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index 91eef749..abf930ea 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -115,6 +115,13 @@ typedef uint32_t pa_volume_t;
/** Maximum valid volume we can store. \since 0.9.15 */
#define PA_VOLUME_MAX ((pa_volume_t) UINT32_MAX/2)
+/** Recommended maximum volume to show in user facing UIs.
+ * Note: UIs should deal gracefully with volumes greater than this value
+ * and not cause feedback loops etc. - i.e. if the volume is more than
+ * this, the UI should not limit it and push the limited value back to
+ * the server. \since 0.9.23 */
+#define PA_VOLUME_UI_MAX (pa_sw_volume_from_dB(+11.0))
+
/** Special 'invalid' volume. \since 0.9.16 */
#define PA_VOLUME_INVALID ((pa_volume_t) UINT32_MAX)
diff --git a/src/pulsecore/asyncq.c b/src/pulsecore/asyncq.c
index e62d0c16..8c2d58a0 100644
--- a/src/pulsecore/asyncq.c
+++ b/src/pulsecore/asyncq.c
@@ -26,6 +26,8 @@
#include <unistd.h>
#include <errno.h>
+#include <pulse/xmalloc.h>
+
#include <pulsecore/atomic.h>
#include <pulsecore/log.h>
#include <pulsecore/thread.h>
@@ -33,10 +35,9 @@
#include <pulsecore/core-util.h>
#include <pulsecore/llist.h>
#include <pulsecore/flist.h>
-#include <pulse/xmalloc.h>
+#include <pulsecore/fdsem.h>
#include "asyncq.h"
-#include "fdsem.h"
#define ASYNCQ_SIZE 256
diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c
index 2f0a3af0..feaa4440 100644
--- a/src/pulsecore/card.c
+++ b/src/pulsecore/card.c
@@ -241,6 +241,8 @@ int pa_card_set_profile(pa_card *c, const char *name, pa_bool_t save) {
c->active_profile = profile;
c->save_profile = save;
+ pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], c);
+
return 0;
}
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index a18ebd33..de4995eb 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -32,6 +32,7 @@
#include <ltdl.h>
#include <sys/stat.h>
#include <dirent.h>
+#include <time.h>
#include <pulse/xmalloc.h>
#include <pulse/error.h>
@@ -579,11 +580,16 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb
return -1;
}
- if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
+ if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) {
pa_strbuf_puts(buf, "No sink input found with this index.\n");
return -1;
}
+ if (!pa_sink_input_is_volume_writable(si)) {
+ pa_strbuf_puts(buf, "This sink input's volume can't be changed.\n");
+ return -1;
+ }
+
pa_cvolume_set(&cvolume, 1, volume);
pa_sink_input_set_volume(si, &cvolume, TRUE, TRUE);
return 0;
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 23a57d37..e6018da2 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -553,8 +553,7 @@ char *pa_sink_input_list_to_string(pa_core *c) {
pa_usec_t cl;
const char *cmn;
pa_cvolume v;
-
- pa_sink_input_get_volume(i, &v, TRUE);
+ char *volume_str = NULL;
cmn = pa_channel_map_to_pretty_name(&i->channel_map);
@@ -565,6 +564,15 @@ char *pa_sink_input_list_to_string(pa_core *c) {
pa_assert(i->sink);
+ if (pa_sink_input_is_volume_readable(i)) {
+ pa_sink_input_get_volume(i, &v, TRUE);
+ volume_str = pa_sprintf_malloc("%s\n\t %s\n\t balance %0.2f",
+ pa_cvolume_snprint(cv, sizeof(cv), &v),
+ pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &v),
+ pa_cvolume_get_balance(&v, &i->channel_map));
+ } else
+ volume_str = pa_xstrdup("n/a");
+
pa_strbuf_printf(
s,
" index: %u\n"
@@ -573,8 +581,6 @@ char *pa_sink_input_list_to_string(pa_core *c) {
"\tstate: %s\n"
"\tsink: %u <%s>\n"
"\tvolume: %s\n"
- "\t %s\n"
- "\t balance %0.2f\n"
"\tmuted: %s\n"
"\tcurrent latency: %0.2f ms\n"
"\trequested latency: %s\n"
@@ -596,9 +602,7 @@ char *pa_sink_input_list_to_string(pa_core *c) {
i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND ? "KILL_ON_SUSPEND " : "",
state_table[pa_sink_input_get_state(i)],
i->sink->index, i->sink->name,
- pa_cvolume_snprint(cv, sizeof(cv), &v),
- pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &v),
- pa_cvolume_get_balance(&v, &i->channel_map),
+ volume_str,
pa_yes_no(pa_sink_input_get_mute(i)),
(double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC,
clt,
@@ -608,6 +612,8 @@ char *pa_sink_input_list_to_string(pa_core *c) {
cmn ? cmn : "",
pa_resample_method_to_string(pa_sink_input_get_resample_method(i)));
+ pa_xfree(volume_str);
+
if (i->module)
pa_strbuf_printf(s, "\tmodule: %u\n", i->module->index);
if (i->client)
diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c
index 5ec6159d..1aed9077 100644
--- a/src/pulsecore/core-scache.c
+++ b/src/pulsecore/core-scache.c
@@ -32,6 +32,7 @@
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
+#include <time.h>
#ifdef HAVE_GLOB_H
#include <glob.h>
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index fd3cc67a..b5043a38 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -222,12 +222,12 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
#ifdef OS_IS_WIN32
r = mkdir(dir);
#else
- {
+{
mode_t u;
u = umask((~m) & 0777);
r = mkdir(dir, m);
umask(u);
- }
+}
#endif
if (r < 0 && errno != EEXIST)
@@ -549,7 +549,7 @@ void pa_check_signal_is_blocked(int sig) {
/* The following function is based on an example from the GNU libc
* documentation. This function is similar to GNU's asprintf(). */
char *pa_sprintf_malloc(const char *format, ...) {
- size_t size = 100;
+ size_t size = 100;
char *c = NULL;
pa_assert(format);
@@ -579,7 +579,7 @@ char *pa_sprintf_malloc(const char *format, ...) {
/* Same as the previous function, but use a va_list instead of an
* ellipsis */
char *pa_vsprintf_malloc(const char *format, va_list ap) {
- size_t size = 100;
+ size_t size = 100;
char *c = NULL;
pa_assert(format);
@@ -625,6 +625,7 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
return b;
}
+#ifdef _POSIX_PRIORITY_SCHEDULING
static int set_scheduler(int rtprio) {
#ifdef HAVE_SCHED_H
struct sched_param sp;
@@ -682,6 +683,7 @@ static int set_scheduler(int rtprio) {
return -1;
}
+#endif
/* Make the current thread a realtime thread, and acquire the highest
* rtprio we can get that is less or equal the specified parameter. If
@@ -718,6 +720,7 @@ int pa_make_realtime(int rtprio) {
return -1;
}
+#ifdef HAVE_SYS_RESOURCE_H
static int set_nice(int nice_level) {
#ifdef HAVE_DBUS
DBusError error;
@@ -762,6 +765,7 @@ static int set_nice(int nice_level) {
return -1;
}
+#endif
/* Raise the priority of the current process as much as possible that
* is <= the specified nice level..*/
@@ -1044,8 +1048,7 @@ static int is_group(gid_t gid, const char *name) {
int r = -1;
errno = 0;
- if (!(group = pa_getgrgid_malloc(gid)))
- {
+ if (!(group = pa_getgrgid_malloc(gid))) {
if (!errno)
errno = ENOENT;
@@ -1111,8 +1114,7 @@ int pa_uid_in_group(uid_t uid, const char *name) {
int r = -1;
errno = 0;
- if (!(group = pa_getgrnam_malloc(name)))
- {
+ if (!(group = pa_getgrnam_malloc(name))) {
if (!errno)
errno = ENOENT;
goto finish;
@@ -1147,8 +1149,7 @@ gid_t pa_get_gid_of_group(const char *name) {
struct group *gr = NULL;
errno = 0;
- if (!(gr = pa_getgrnam_malloc(name)))
- {
+ if (!(gr = pa_getgrnam_malloc(name))) {
if (!errno)
errno = ENOENT;
goto finish;
@@ -1396,7 +1397,7 @@ char *pa_get_state_dir(void) {
/* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same
* dir then this will break. */
- if (pa_make_secure_dir(d, 0700U, (uid_t) -1, (gid_t) -1) < 0) {
+ if (pa_make_secure_dir(d, 0700U, (uid_t) -1, (gid_t) -1) < 0) {
pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
pa_xfree(d);
return NULL;
@@ -1536,7 +1537,7 @@ char *pa_get_runtime_dir(void) {
if ((d = getenv("PULSE_RUNTIME_PATH"))) {
- if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
+ if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
goto fail;
}
@@ -1547,7 +1548,7 @@ char *pa_get_runtime_dir(void) {
if (!(d = get_pulse_home()))
goto fail;
- if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
+ if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
pa_xfree(d);
goto fail;
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index a1215bb5..358b98d7 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -74,6 +74,7 @@ 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_PORT_CHANGED,
PA_CORE_HOOK_SOURCE_NEW,
PA_CORE_HOOK_SOURCE_FIXATE,
PA_CORE_HOOK_SOURCE_PUT,
@@ -81,6 +82,7 @@ typedef enum pa_core_hook {
PA_CORE_HOOK_SOURCE_UNLINK_POST,
PA_CORE_HOOK_SOURCE_STATE_CHANGED,
PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED,
+ PA_CORE_HOOK_SOURCE_PORT_CHANGED,
PA_CORE_HOOK_SINK_INPUT_NEW,
PA_CORE_HOOK_SINK_INPUT_FIXATE,
PA_CORE_HOOK_SINK_INPUT_PUT,
@@ -111,6 +113,7 @@ typedef enum pa_core_hook {
PA_CORE_HOOK_CARD_NEW,
PA_CORE_HOOK_CARD_PUT,
PA_CORE_HOOK_CARD_UNLINK,
+ PA_CORE_HOOK_CARD_PROFILE_CHANGED,
PA_CORE_HOOK_MAX
} pa_core_hook_t;
diff --git a/src/pulsecore/cpu-arm.c b/src/pulsecore/cpu-arm.c
index 1d0d7651..0287043e 100644
--- a/src/pulsecore/cpu-arm.c
+++ b/src/pulsecore/cpu-arm.c
@@ -37,24 +37,24 @@
#if defined (__arm__) && defined (__linux__)
-#define MAX_BUFFER 4096
+#define MAX_BUFFER 4096
static char *
-get_cpuinfo_line (char *cpuinfo, const char *tag) {
+get_cpuinfo_line(char *cpuinfo, const char *tag) {
char *line, *end, *colon;
- if (!(line = strstr (cpuinfo, tag)))
+ if (!(line = strstr(cpuinfo, tag)))
return NULL;
- if (!(end = strchr (line, '\n')))
+ if (!(end = strchr(line, '\n')))
return NULL;
- if (!(colon = strchr (line, ':')))
+ if (!(colon = strchr(line, ':')))
return NULL;
if (++colon >= end)
return NULL;
- return pa_xstrndup (colon, end - colon);
+ return pa_xstrndup(colon, end - colon);
}
static char *get_cpuinfo(void) {
@@ -80,7 +80,7 @@ static char *get_cpuinfo(void) {
}
#endif /* defined (__arm__) && defined (__linux__) */
-pa_bool_t pa_cpu_init_arm (pa_cpu_arm_flag_t *flags) {
+pa_bool_t pa_cpu_init_arm(pa_cpu_arm_flag_t *flags) {
#if defined (__arm__)
#if defined (__linux__)
char *cpuinfo, *line;
@@ -88,16 +88,16 @@ pa_bool_t pa_cpu_init_arm (pa_cpu_arm_flag_t *flags) {
/* We need to read the CPU flags from /proc/cpuinfo because there is no user
* space support to get the CPU features. This only works on linux AFAIK. */
- if (!(cpuinfo = get_cpuinfo ())) {
- pa_log ("Can't read cpuinfo");
+ if (!(cpuinfo = get_cpuinfo())) {
+ pa_log("Can't read cpuinfo");
return;
}
*flags = 0;
/* get the CPU architecture */
- if ((line = get_cpuinfo_line (cpuinfo, "CPU architecture"))) {
- arch = strtoul (line, NULL, 0);
+ if ((line = get_cpuinfo_line(cpuinfo, "CPU architecture"))) {
+ arch = strtoul(line, NULL, 0);
if (arch >= 6)
*flags |= PA_CPU_ARM_V6;
if (arch >= 7)
@@ -106,18 +106,18 @@ pa_bool_t pa_cpu_init_arm (pa_cpu_arm_flag_t *flags) {
pa_xfree(line);
}
/* get the CPU features */
- if ((line = get_cpuinfo_line (cpuinfo, "Features"))) {
+ if ((line = get_cpuinfo_line(cpuinfo, "Features"))) {
const char *state = NULL;
char *current;
- while ((current = pa_split_spaces (line, &state))) {
- if (!strcmp (current, "vfp"))
+ while ((current = pa_split_spaces(line, &state))) {
+ if (!strcmp(current, "vfp"))
*flags |= PA_CPU_ARM_VFP;
- else if (!strcmp (current, "edsp"))
+ else if (!strcmp(current, "edsp"))
*flags |= PA_CPU_ARM_EDSP;
- else if (!strcmp (current, "neon"))
+ else if (!strcmp(current, "neon"))
*flags |= PA_CPU_ARM_NEON;
- else if (!strcmp (current, "vfpv3"))
+ else if (!strcmp(current, "vfpv3"))
*flags |= PA_CPU_ARM_VFPV3;
pa_xfree(current);
@@ -125,7 +125,7 @@ pa_bool_t pa_cpu_init_arm (pa_cpu_arm_flag_t *flags) {
}
pa_xfree(cpuinfo);
- pa_log_info ("CPU flags: %s%s%s%s%s%s",
+ pa_log_info("CPU flags: %s%s%s%s%s%s",
(*flags & PA_CPU_ARM_V6) ? "V6 " : "",
(*flags & PA_CPU_ARM_V7) ? "V7 " : "",
(*flags & PA_CPU_ARM_VFP) ? "VFP " : "",
@@ -134,7 +134,7 @@ pa_bool_t pa_cpu_init_arm (pa_cpu_arm_flag_t *flags) {
(*flags & PA_CPU_ARM_VFPV3) ? "VFPV3 " : "");
if (*flags & PA_CPU_ARM_V6)
- pa_volume_func_init_arm (*flags);
+ pa_volume_func_init_arm(*flags);
return TRUE;
diff --git a/src/pulsecore/cpu-orc.c b/src/pulsecore/cpu-orc.c
new file mode 100644
index 00000000..d4a15357
--- /dev/null
+++ b/src/pulsecore/cpu-orc.c
@@ -0,0 +1,34 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#include "cpu-orc.h"
+
+void pa_cpu_init_orc(pa_cpu_info cpu_info)
+{
+#ifndef DISABLE_ORC
+ /* Update these as we test on more architectures */
+ pa_cpu_x86_flag_t x86_want_flags = PA_CPU_X86_MMX | PA_CPU_X86_SSE | PA_CPU_X86_SSE2 | PA_CPU_X86_SSE3 | PA_CPU_X86_SSSE3 | PA_CPU_X86_SSE4_1 | PA_CPU_X86_SSE4_2;
+
+ /* Enable Orc svolume optimizations */
+ if ((cpu_info.cpu_type == PA_CPU_X86) && (cpu_info.flags.x86 & x86_want_flags))
+ pa_volume_func_init_orc();
+#endif
+}
diff --git a/src/pulsecore/cpu-orc.h b/src/pulsecore/cpu-orc.h
new file mode 100644
index 00000000..9924d27b
--- /dev/null
+++ b/src/pulsecore/cpu-orc.h
@@ -0,0 +1,37 @@
+#ifndef foocpuorchfoo
+#define foocpuorchfoo
+
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pulsecore/cpu.h>
+
+/* Orc-optimised bits */
+
+void pa_cpu_init_orc(pa_cpu_info cpu_info);
+
+void pa_volume_func_init_orc(void);
+
+#endif /* foocpuorchfoo */
diff --git a/src/pulsecore/cpu-x86.c b/src/pulsecore/cpu-x86.c
index 062a4c1b..05a4b2f0 100644
--- a/src/pulsecore/cpu-x86.c
+++ b/src/pulsecore/cpu-x86.c
@@ -31,9 +31,7 @@
#include "cpu-x86.h"
#if defined (__i386__) || defined (__amd64__)
-static void
-get_cpuid (uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
-{
+static void get_cpuid(uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) {
__asm__ __volatile__ (
" push %%"PA_REG_b" \n\t"
" cpuid \n\t"
@@ -46,7 +44,7 @@ get_cpuid (uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
}
#endif
-pa_bool_t pa_cpu_init_x86 (pa_cpu_x86_flag_t *flags) {
+pa_bool_t pa_cpu_init_x86(pa_cpu_x86_flag_t *flags) {
#if defined (__i386__) || defined (__amd64__)
uint32_t eax, ebx, ecx, edx;
uint32_t level;
@@ -54,9 +52,9 @@ pa_bool_t pa_cpu_init_x86 (pa_cpu_x86_flag_t *flags) {
*flags = 0;
/* get standard level */
- get_cpuid (0x00000000, &level, &ebx, &ecx, &edx);
+ get_cpuid(0x00000000, &level, &ebx, &ecx, &edx);
if (level >= 1) {
- get_cpuid (0x00000001, &eax, &ebx, &ecx, &edx);
+ get_cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
if (edx & (1<<15))
*flags |= PA_CPU_X86_CMOV;
@@ -84,9 +82,9 @@ pa_bool_t pa_cpu_init_x86 (pa_cpu_x86_flag_t *flags) {
}
/* get extended level */
- get_cpuid (0x80000000, &level, &ebx, &ecx, &edx);
+ get_cpuid(0x80000000, &level, &ebx, &ecx, &edx);
if (level >= 0x80000001) {
- get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx);
+ get_cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
if (edx & (1<<22))
*flags |= PA_CPU_X86_MMXEXT;
@@ -101,7 +99,7 @@ pa_bool_t pa_cpu_init_x86 (pa_cpu_x86_flag_t *flags) {
*flags |= PA_CPU_X86_3DNOW;
}
- pa_log_info ("CPU flags: %s%s%s%s%s%s%s%s%s%s%s",
+ pa_log_info("CPU flags: %s%s%s%s%s%s%s%s%s%s%s",
(*flags & PA_CPU_X86_CMOV) ? "CMOV " : "",
(*flags & PA_CPU_X86_MMX) ? "MMX " : "",
(*flags & PA_CPU_X86_SSE) ? "SSE " : "",
@@ -116,14 +114,14 @@ pa_bool_t pa_cpu_init_x86 (pa_cpu_x86_flag_t *flags) {
/* activate various optimisations */
if (*flags & PA_CPU_X86_MMX) {
- pa_volume_func_init_mmx (*flags);
- pa_remap_func_init_mmx (*flags);
+ pa_volume_func_init_mmx(*flags);
+ pa_remap_func_init_mmx(*flags);
}
if (*flags & (PA_CPU_X86_SSE | PA_CPU_X86_SSE2)) {
- pa_volume_func_init_sse (*flags);
- pa_remap_func_init_sse (*flags);
- pa_convert_func_init_sse (*flags);
+ pa_volume_func_init_sse(*flags);
+ pa_remap_func_init_sse(*flags);
+ pa_convert_func_init_sse(*flags);
}
return TRUE;
diff --git a/src/pulsecore/database-simple.c b/src/pulsecore/database-simple.c
index 754930db..237d0bdd 100644
--- a/src/pulsecore/database-simple.c
+++ b/src/pulsecore/database-simple.c
@@ -429,7 +429,7 @@ static int write_uint(FILE *f, const uint32_t num) {
errno = 0;
for (i = 0; i < 4; i++)
- values[i] = (num >> (i*8)) & 0xFF;
+ values[i] = (num >> (i*8)) & 0xFF;
items = fwrite(&values, sizeof(values), sizeof(uint8_t), f);
diff --git a/src/pulsecore/envelope.c b/src/pulsecore/envelope.c
deleted file mode 100644
index 75e189cb..00000000
--- a/src/pulsecore/envelope.c
+++ /dev/null
@@ -1,989 +0,0 @@
-/***
- This file is part of PulseAudio.
-
- Copyright 2007 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.1 of the
- License, or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser 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 <stdio.h>
-
-#include <pulse/sample.h>
-#include <pulse/xmalloc.h>
-
-#include <pulsecore/endianmacros.h>
-#include <pulsecore/memchunk.h>
-#include <pulsecore/macro.h>
-#include <pulsecore/flist.h>
-#include <pulsecore/semaphore.h>
-#include <pulsecore/g711.h>
-
-#include "envelope.h"
-
-/*
- Envelope subsystem for applying linear interpolated volume
- envelopes on audio data. If multiple enevelopes shall be applied
- at the same time, the "minimum" envelope is determined and
- applied.
-
- Envelopes are defined in a statically allocated constant structure
- pa_envelope_def. It may be activated using pa_envelope_add(). And
- already active envelope may be replaced with pa_envelope_replace()
- and removed with pa_envelope_remove().The combined "minimum"
- envelope can be applied to audio data with pa_envelope_apply().
-
- _apply() on one hand and _add()/_replace()/_remove() on the other
- can be executed in seperate threads, in which case no locking is
- used.
-*/
-
-PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
-
-struct pa_envelope_item {
- PA_LLIST_FIELDS(pa_envelope_item);
- const pa_envelope_def *def;
- pa_usec_t start_x;
- union {
- int32_t i;
- float f;
- } start_y;
- unsigned j;
-};
-
-enum envelope_state {
- STATE_VALID0,
- STATE_VALID1,
- STATE_READ0,
- STATE_READ1,
- STATE_WAIT0,
- STATE_WAIT1,
- STATE_WRITE0,
- STATE_WRITE1
-};
-
-struct pa_envelope {
- pa_sample_spec sample_spec;
-
- PA_LLIST_HEAD(pa_envelope_item, items);
-
- pa_atomic_t state;
-
- size_t x;
-
- struct {
- unsigned n_points, n_allocated, n_current;
-
- size_t *x;
- union {
- int32_t *i;
- float *f;
- } y;
-
- size_t cached_dx;
- int32_t cached_dy_i;
- float cached_dy_dx;
- pa_bool_t cached_valid;
- } points[2];
-
- pa_bool_t is_float;
-
- pa_semaphore *semaphore;
-};
-
-pa_envelope *pa_envelope_new(const pa_sample_spec *ss) {
- pa_envelope *e;
- pa_assert(ss);
-
- e = pa_xnew(pa_envelope, 1);
-
- e->sample_spec = *ss;
- PA_LLIST_HEAD_INIT(pa_envelope_item, e->items);
-
- e->x = 0;
-
- e->points[0].n_points = e->points[1].n_points = 0;
- e->points[0].n_allocated = e->points[1].n_allocated = 0;
- e->points[0].n_current = e->points[1].n_current = 0;
- e->points[0].x = e->points[1].x = NULL;
- e->points[0].y.i = e->points[1].y.i = NULL;
- e->points[0].cached_valid = e->points[1].cached_valid = FALSE;
-
- pa_atomic_store(&e->state, STATE_VALID0);
-
- e->is_float =
- ss->format == PA_SAMPLE_FLOAT32LE ||
- ss->format == PA_SAMPLE_FLOAT32BE;
-
- e->semaphore = pa_semaphore_new(0);
-
- return e;
-}
-
-void pa_envelope_free(pa_envelope *e) {
- pa_assert(e);
-
- while (e->items)
- pa_envelope_remove(e, e->items);
-
- pa_xfree(e->points[0].x);
- pa_xfree(e->points[1].x);
- pa_xfree(e->points[0].y.i);
- pa_xfree(e->points[1].y.i);
-
- pa_semaphore_free(e->semaphore);
-
- pa_xfree(e);
-}
-
-static int32_t linear_interpolate_int(pa_usec_t x1, int32_t _y1, pa_usec_t x2, int32_t y2, pa_usec_t x3) {
- return (int32_t) ((double) _y1 + (double) (x3 - x1) * (double) (y2 - _y1) / (double) (x2 - x1));
-}
-
-static float linear_interpolate_float(pa_usec_t x1, float _y1, pa_usec_t x2, float y2, pa_usec_t x3) {
- return _y1 + ((float) x3 - (float) x1) * (y2 - _y1) / ((float) x2 - (float) x1);
-}
-
-static int32_t item_get_int(pa_envelope_item *i, pa_usec_t x) {
- pa_assert(i);
-
- if (x <= i->start_x)
- return i->start_y.i;
-
- x -= i->start_x;
-
- if (x <= i->def->points_x[0])
- return linear_interpolate_int(0, i->start_y.i,
- i->def->points_x[0], i->def->points_y.i[0], x);
-
- if (x >= i->def->points_x[i->def->n_points-1])
- return i->def->points_y.i[i->def->n_points-1];
-
- pa_assert(i->j > 0);
- pa_assert(i->def->points_x[i->j-1] <= x);
- pa_assert(x <= i->def->points_x[i->j]);
-
- return linear_interpolate_int(i->def->points_x[i->j-1], i->def->points_y.i[i->j-1],
- i->def->points_x[i->j], i->def->points_y.i[i->j], x);
-}
-
-static float item_get_float(pa_envelope_item *i, pa_usec_t x) {
- pa_assert(i);
-
- if (x <= i->start_x)
- return i->start_y.f;
-
- x -= i->start_x;
-
- if (x <= i->def->points_x[0])
- return linear_interpolate_float(0, i->start_y.f,
- i->def->points_x[0], i->def->points_y.f[0], x);
-
- if (x >= i->def->points_x[i->def->n_points-1])
- return i->def->points_y.f[i->def->n_points-1];
-
- pa_assert(i->j > 0);
- pa_assert(i->def->points_x[i->j-1] <= x);
- pa_assert(x <= i->def->points_x[i->j]);
-
- return linear_interpolate_float(i->def->points_x[i->j-1], i->def->points_y.f[i->j-1],
- i->def->points_x[i->j], i->def->points_y.f[i->j], x);
-}
-
-static void envelope_begin_write(pa_envelope *e, int *v) {
- enum envelope_state new_state, old_state;
- pa_bool_t wait_sem;
-
- pa_assert(e);
- pa_assert(v);
-
- for (;;) {
- do {
- wait_sem = FALSE;
- old_state = pa_atomic_load(&e->state);
-
- switch (old_state) {
- case STATE_VALID0:
- *v = 1;
- new_state = STATE_WRITE0;
- break;
- case STATE_VALID1:
- *v = 0;
- new_state = STATE_WRITE1;
- break;
- case STATE_READ0:
- new_state = STATE_WAIT0;
- wait_sem = TRUE;
- break;
- case STATE_READ1:
- new_state = STATE_WAIT1;
- wait_sem = TRUE;
- break;
- default:
- pa_assert_not_reached();
- }
- } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
-
- if (!wait_sem)
- break;
-
- pa_semaphore_wait(e->semaphore);
- }
-}
-
-static pa_bool_t envelope_commit_write(pa_envelope *e, int v) {
- enum envelope_state new_state, old_state;
-
- pa_assert(e);
-
- do {
- old_state = pa_atomic_load(&e->state);
-
- switch (old_state) {
- case STATE_WRITE0:
- pa_assert(v == 1);
- new_state = STATE_VALID1;
- break;
- case STATE_WRITE1:
- pa_assert(v == 0);
- new_state = STATE_VALID0;
- break;
- case STATE_VALID0:
- case STATE_VALID1:
- case STATE_READ0:
- case STATE_READ1:
- return FALSE;
- default:
- pa_assert_not_reached();
- }
- } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
-
- return TRUE;
-}
-
-static void envelope_begin_read(pa_envelope *e, int *v) {
- enum envelope_state new_state, old_state;
- pa_assert(e);
- pa_assert(v);
-
- do {
- old_state = pa_atomic_load(&e->state);
-
- switch (old_state) {
- case STATE_VALID0:
- case STATE_WRITE0:
- *v = 0;
- new_state = STATE_READ0;
- break;
- case STATE_VALID1:
- case STATE_WRITE1:
- *v = 1;
- new_state = STATE_READ1;
- break;
- default:
- pa_assert_not_reached();
- }
- } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
-}
-
-static void envelope_commit_read(pa_envelope *e, int v) {
- enum envelope_state new_state, old_state;
- pa_bool_t post_sem;
-
- pa_assert(e);
-
- do {
- post_sem = FALSE;
- old_state = pa_atomic_load(&e->state);
-
- switch (old_state) {
- case STATE_READ0:
- pa_assert(v == 0);
- new_state = STATE_VALID0;
- break;
- case STATE_READ1:
- pa_assert(v == 1);
- new_state = STATE_VALID1;
- break;
- case STATE_WAIT0:
- pa_assert(v == 0);
- new_state = STATE_VALID0;
- post_sem = TRUE;
- break;
- case STATE_WAIT1:
- pa_assert(v == 1);
- new_state = STATE_VALID1;
- post_sem = TRUE;
- break;
- default:
- pa_assert_not_reached();
- }
- } while (!pa_atomic_cmpxchg(&e->state, old_state, new_state));
-
- if (post_sem)
- pa_semaphore_post(e->semaphore);
-}
-
-static void envelope_merge(pa_envelope *e, int v) {
-
- e->points[v].n_points = 0;
-
- if (e->items) {
- pa_envelope_item *i;
- pa_usec_t x = (pa_usec_t) -1;
-
- for (i = e->items; i; i = i->next)
- i->j = 0;
-
- for (;;) {
- pa_bool_t min_is_set;
- pa_envelope_item *s = NULL;
-
- /* Let's find the next spot on the X axis to analyze */
- for (i = e->items; i; i = i->next) {
-
- for (;;) {
-
- if (i->j >= i->def->n_points)
- break;
-
- if ((x != (pa_usec_t) -1) && i->start_x + i->def->points_x[i->j] <= x) {
- i->j++;
- continue;
- }
-
- if (!s || (i->start_x + i->def->points_x[i->j] < s->start_x + s->def->points_x[s->j]))
- s = i;
-
- break;
- }
- }
-
- if (!s)
- break;
-
- if (e->points[v].n_points >= e->points[v].n_allocated) {
- e->points[v].n_allocated = PA_MAX(e->points[v].n_points*2, PA_ENVELOPE_POINTS_MAX);
-
- e->points[v].x = pa_xrealloc(e->points[v].x, sizeof(size_t) * e->points[v].n_allocated);
- e->points[v].y.i = pa_xrealloc(e->points[v].y.i, sizeof(int32_t) * e->points[v].n_allocated);
- }
-
- x = s->start_x + s->def->points_x[s->j];
- e->points[v].x[e->points[v].n_points] = pa_usec_to_bytes(x, &e->sample_spec);
-
- min_is_set = FALSE;
-
- /* Now let's find the lowest value */
- if (e->is_float) {
- float min_f;
-
- for (i = e->items; i; i = i->next) {
- float f = item_get_float(i, x);
- if (!min_is_set || f < min_f) {
- min_f = f;
- min_is_set = TRUE;
- }
- }
-
- e->points[v].y.f[e->points[v].n_points] = min_f;
- } else {
- int32_t min_k;
-
- for (i = e->items; i; i = i->next) {
- int32_t k = item_get_int(i, x);
- if (!min_is_set || k < min_k) {
- min_k = k;
- min_is_set = TRUE;
- }
- }
-
- e->points[v].y.i[e->points[v].n_points] = min_k;
- }
-
- pa_assert_se(min_is_set);
- e->points[v].n_points++;
- }
- }
-
- e->points[v].n_current = 0;
- e->points[v].cached_valid = FALSE;
-}
-
-pa_envelope_item *pa_envelope_add(pa_envelope *e, const pa_envelope_def *def) {
- pa_envelope_item *i;
- int v;
-
- pa_assert(e);
- pa_assert(def);
- pa_assert(def->n_points > 0);
-
- if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
- i = pa_xnew(pa_envelope_item, 1);
-
- i->def = def;
-
- if (e->is_float)
- i->start_y.f = def->points_y.f[0];
- else
- i->start_y.i = def->points_y.i[0];
-
- PA_LLIST_PREPEND(pa_envelope_item, e->items, i);
-
- envelope_begin_write(e, &v);
-
- do {
-
- i->start_x = pa_bytes_to_usec(e->x, &e->sample_spec);
- envelope_merge(e, v);
-
- } while (!envelope_commit_write(e, v));
-
- return i;
-}
-
-pa_envelope_item *pa_envelope_replace(pa_envelope *e, pa_envelope_item *i, const pa_envelope_def *def) {
- pa_usec_t x;
- int v;
-
- pa_assert(e);
- pa_assert(i);
- pa_assert(def->n_points > 0);
-
- envelope_begin_write(e, &v);
-
- for (;;) {
- float saved_f;
- int32_t saved_i;
- uint64_t saved_start_x;
- const pa_envelope_def *saved_def;
-
- x = pa_bytes_to_usec(e->x, &e->sample_spec);
-
- if (e->is_float) {
- saved_f = i->start_y.f;
- i->start_y.f = item_get_float(i, x);
- } else {
- saved_i = i->start_y.i;
- i->start_y.i = item_get_int(i, x);
- }
-
- saved_start_x = i->start_x;
- saved_def = i->def;
-
- i->start_x = x;
- i->def = def;
-
- envelope_merge(e, v);
-
- if (envelope_commit_write(e, v))
- break;
-
- i->start_x = saved_start_x;
- i->def = saved_def;
-
- if (e->is_float)
- i->start_y.f = saved_f;
- else
- i->start_y.i = saved_i;
- }
-
- return i;
-}
-
-void pa_envelope_remove(pa_envelope *e, pa_envelope_item *i) {
- int v;
-
- pa_assert(e);
- pa_assert(i);
-
- PA_LLIST_REMOVE(pa_envelope_item, e->items, i);
-
- if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
- pa_xfree(i);
-
- envelope_begin_write(e, &v);
- do {
- envelope_merge(e, v);
- } while (!envelope_commit_write(e, v));
-}
-
-static int32_t linear_get_int(pa_envelope *e, int v) {
- pa_assert(e);
-
- /* The repeated division could be replaced by Bresenham, as an
- * optimization */
-
- if (e->x < e->points[v].x[0])
- return e->points[v].y.i[0];
-
- for (;;) {
- if (e->points[v].n_current+1 >= e->points[v].n_points)
- return e->points[v].y.i[e->points[v].n_points-1];
-
- if (e->x < e->points[v].x[e->points[v].n_current+1])
- break;
-
- e->points[v].n_current++;
- e->points[v].cached_valid = FALSE;
- }
-
- if (!e->points[v].cached_valid) {
- e->points[v].cached_dx = e->points[v].x[e->points[v].n_current+1] - e->points[v].x[e->points[v].n_current];
- e->points[v].cached_dy_i = e->points[v].y.i[e->points[v].n_current+1] - e->points[v].y.i[e->points[v].n_current];
- e->points[v].cached_valid = TRUE;
- }
-
- return e->points[v].y.i[e->points[v].n_current] + ((float)e->points[v].cached_dy_i * (int32_t) (e->x - e->points[v].x[e->points[v].n_current])) / (int32_t) e->points[v].cached_dx;
-}
-
-static float linear_get_float(pa_envelope *e, int v) {
- pa_assert(e);
-
- if (e->x < e->points[v].x[0])
- return e->points[v].y.f[0];
-
- for (;;) {
- if (e->points[v].n_current+1 >= e->points[v].n_points)
- return e->points[v].y.f[e->points[v].n_points-1];
-
- if (e->x < e->points[v].x[e->points[v].n_current+1])
- break;
-
- e->points[v].n_current++;
- e->points[v].cached_valid = FALSE;
- }
-
- if (!e->points[v].cached_valid) {
- e->points[v].cached_dy_dx =
- (e->points[v].y.f[e->points[v].n_current+1] - e->points[v].y.f[e->points[v].n_current]) /
- ((float) e->points[v].x[e->points[v].n_current+1] - (float) e->points[v].x[e->points[v].n_current]);
- e->points[v].cached_valid = TRUE;
- }
-
- return e->points[v].y.f[e->points[v].n_current] + (float) (e->x - e->points[v].x[e->points[v].n_current]) * e->points[v].cached_dy_dx;
-}
-
-void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) {
- int v;
-
- pa_assert(e);
- pa_assert(chunk);
-
- envelope_begin_read(e, &v);
-
- if (e->points[v].n_points > 0) {
- void *p;
- size_t fs, n;
-
- pa_memchunk_make_writable(chunk, 0);
- p = (uint8_t*) pa_memblock_acquire(chunk->memblock) + chunk->index;
- fs = pa_frame_size(&e->sample_spec);
- n = chunk->length;
-
- pa_log_debug("Envelop position %zu applying factor %d=%f, sample spec is %d, chunk's length is %zu, fs is %zu\n", e->x, linear_get_int(e, v), ((float) linear_get_int(e,v))/0x10000, e->sample_spec.format, n, fs);
-
- switch (e->sample_spec.format) {
-
- case PA_SAMPLE_U8: {
- uint8_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (uint8_t*) p + n;
-
- for (channel = 0, d = p; d < s; d++) {
- int32_t t, hi, lo;
-
- hi = factor >> 16;
- lo = factor & 0xFFFF;
-
- t = (int32_t) *d - 0x80;
- t = ((t * lo) >> 16) + (t * hi);
- t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F);
- *d = (uint8_t) (t + 0x80);
-
- if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
- channel = 0;
- e->x += fs;
- factor = linear_get_int(e, v);
- }
- }
-
- break;
- }
-
- case PA_SAMPLE_ULAW: {
- uint8_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (uint8_t*) p + n;
-
- for (channel = 0, d = p; d < s; d++) {
- int32_t t, hi, lo;
-
- hi = factor >> 16;
- lo = factor & 0xFFFF;
-
- t = (int32_t) st_ulaw2linear16(*d);
- t = ((t * lo) >> 16) + (t * hi);
- t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
- *d = (uint8_t) st_14linear2ulaw((int16_t) t >> 2);
-
- if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
- channel = 0;
- e->x += fs;
- factor = linear_get_int(e, v);
- }
- }
-
- break;
- }
-
- case PA_SAMPLE_ALAW: {
- uint8_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (uint8_t*) p + n;
-
- for (channel = 0, d = p; d < s; d++) {
- int32_t t, hi, lo;
-
- hi = factor >> 16;
- lo = factor & 0xFFFF;
-
- t = (int32_t) st_alaw2linear16(*d);
- t = ((t * lo) >> 16) + (t * hi);
- t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
- *d = (uint8_t) st_13linear2alaw((int16_t) t >> 3);
-
- if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
- channel = 0;
- e->x += fs;
- factor = linear_get_int(e, v);
- }
- }
-
- break;
- }
-
- case PA_SAMPLE_S16NE: {
- int16_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (int16_t*) p + n/sizeof(int16_t);
-
- for (channel = 0, d = p; d < s; d++) {
- int32_t t, hi, lo;
-
- hi = factor >> 16;
- lo = factor & 0xFFFF;
-
- t = (int32_t)(*d);
- t = ((t * lo) >> 16) + (t * hi);
- t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
- *d = (int16_t) t;
-
- if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
- channel = 0;
- e->x += fs;
- factor = linear_get_int(e, v);
- }
- }
-
- break;
- }
-
- case PA_SAMPLE_S16RE: {
- int16_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (int16_t*) p + n/sizeof(int16_t);
-
- for (channel = 0, d = p; d < s; d++) {
- int32_t t, hi, lo;
-
- hi = factor >> 16;
- lo = factor & 0xFFFF;
-
- t = (int32_t) PA_INT16_SWAP(*d);
- t = ((t * lo) >> 16) + (t * hi);
- t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
- *d = PA_INT16_SWAP((int16_t) t);
-
- if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
- channel = 0;
- e->x += fs;
- factor = linear_get_int(e, v);
- }
- }
-
- break;
- }
-
- case PA_SAMPLE_S32NE: {
- int32_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (int32_t*) p + n/sizeof(int32_t);
-
- for (channel = 0, d = p; d < s; d++) {
- int64_t t;
-
- t = (int64_t)(*d);
- t = (t * factor) >> 16;
- t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
- *d = (int32_t) t;
-
- if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
- channel = 0;
- e->x += fs;
- factor = linear_get_int(e, v);
- }
- }
-
- break;
- }
-
- case PA_SAMPLE_S32RE: {
- int32_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (int32_t*) p + n/sizeof(int32_t);
-
- for (channel = 0, d = p; d < s; d++) {
- int64_t t;
-
- t = (int64_t) PA_INT32_SWAP(*d);
- t = (t * factor) >> 16;
- t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
- *d = PA_INT32_SWAP((int32_t) t);
-
- if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
- channel = 0;
- e->x += fs;
- factor = linear_get_int(e, v);
- }
- }
-
- break;
- }
-
- case PA_SAMPLE_FLOAT32NE: {
- /*Seems the FLOAT32NE part of pa_volume_memchunk not right, do not reuse here*/
- float *t;
-
- for (t = p; n > 0; n -= fs) {
- float factor = linear_get_float(e, v);
- unsigned c;
- e->x += fs;
-
- for (c = 0; c < e->sample_spec.channels; c++, t++)
- *t = *t * factor;
- }
-
- break;
- }
-
- case PA_SAMPLE_FLOAT32RE: {
- /*Seems the FLOAT32RE part of pa_volume_memchunk not right, do not reuse here*/
- float *t;
-
- for (t = p; n > 0; n -= fs) {
- float factor = linear_get_float(e, v);
- unsigned c;
- e->x += fs;
-
- for (c = 0; c < e->sample_spec.channels; c++, t++) {
- float r = PA_FLOAT32_SWAP(*t) * factor;
- *t = PA_FLOAT32_SWAP(r);
- }
- }
-
- break;
- }
-
- case PA_SAMPLE_S24NE: {
- uint8_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (uint8_t*) p + n/3;
-
- for (channel = 0, d = p; d < s; d++) {
- int64_t t;
-
- t = (int64_t)((int32_t) (PA_READ24NE(d) << 8));
- t = (t * factor) >> 16;
- t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
- PA_WRITE24NE(d, ((uint32_t) (int32_t) t) >> 8);
-
- if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
- channel = 0;
- e->x += fs;
- factor = linear_get_int(e, v);
- }
- }
-
- break;
- }
- case PA_SAMPLE_S24RE: {
- uint8_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (uint8_t*) p + n/3;
-
- for (channel = 0, d = p; d < s; d++) {
- int64_t t;
-
- t = (int64_t)((int32_t) (PA_READ24RE(d) << 8));
- t = (t * factor) >> 16;
- t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
- PA_WRITE24RE(d, ((uint32_t) (int32_t) t) >> 8);
-
- if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
- channel = 0;
- e->x += fs;
- factor = linear_get_int(e, v);
- }
- }
-
- break;
- }
- case PA_SAMPLE_S24_32NE: {
- uint32_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (uint32_t*) p + n/sizeof(uint32_t);
-
- for (channel = 0, d = p; d < s; d++) {
- int64_t t;
-
- t = (int64_t) ((int32_t) (*d << 8));
- t = (t * factor) >> 16;
- t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
- *d = ((uint32_t) ((int32_t) t)) >> 8;
-
- if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
- channel = 0;
- e->x += fs;
- factor = linear_get_int(e, v);
- }
- }
-
- break;
- }
- case PA_SAMPLE_S24_32RE: {
- uint32_t *d, *s;
- unsigned channel;
- int32_t factor = linear_get_int(e, v);
-
- s = (uint32_t*) p + n/sizeof(uint32_t);
-
- for (channel = 0, d = p; d < s; d++) {
- int64_t t;
-
- t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*d) << 8));
- t = (t * factor) >> 16;
- t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
- *d = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8);
-
- if (PA_UNLIKELY(++channel >= e->sample_spec.channels)) {
- channel = 0;
- e->x += fs;
- factor = linear_get_int(e, v);
- }
- }
- break;
- }
- /* FIXME */
- pa_assert_not_reached();
-
- case PA_SAMPLE_MAX:
- case PA_SAMPLE_INVALID:
- pa_assert_not_reached();
- }
-
- pa_memblock_release(chunk->memblock);
- } else {
- /* When we have no envelope to apply we reset our origin */
- e->x = 0;
- }
-
- envelope_commit_read(e, v);
-}
-
-void pa_envelope_rewind(pa_envelope *e, size_t n_bytes) {
- int v;
-
- pa_assert(e);
-
- envelope_begin_read(e, &v);
-
- if (e->x - n_bytes <= e->points[v].x[0])
- e->x = e->points[v].x[0];
- else
- e->x -= n_bytes;
-
- e->points[v].n_current = 0;
- e->points[v].cached_valid = FALSE;
-
- envelope_commit_read(e, v);
-}
-
-void pa_envelope_restart(pa_envelope* e) {
- int v;
- pa_assert(e);
-
- envelope_begin_read(e, &v);
- e->x = e->points[v].x[0];
- envelope_commit_read(e, v);
-}
-
-pa_bool_t pa_envelope_is_finished(pa_envelope* e) {
- int v;
- pa_bool_t finished;
-
- pa_assert(e);
- envelope_begin_read(e, &v);
- finished = (e->x >= e->points[v].x[e->points[v].n_points-1]);
- envelope_commit_read(e, v);
-
- return finished;
-}
-
-int32_t pa_envelope_length(pa_envelope *e) {
- int v;
- size_t size;
-
- pa_assert(e);
- envelope_begin_read(e, &v);
- size = e->points[v].x[e->points[v].n_points-1] - e->points[v].x[0];
- envelope_commit_read(e, v);
-
- return size;
-}
diff --git a/src/pulsecore/envelope.h b/src/pulsecore/envelope.h
deleted file mode 100644
index 4fa36579..00000000
--- a/src/pulsecore/envelope.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef foopulseenvelopehfoo
-#define foopulseenvelopehfoo
-
-/***
- This file is part of PulseAudio.
-
- Copyright 2007 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.1 of the
- License, or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#include <pulsecore/macro.h>
-#include <pulsecore/memchunk.h>
-
-#include <pulse/sample.h>
-
-#define PA_ENVELOPE_POINTS_MAX 4U
-
-typedef struct pa_envelope pa_envelope;
-typedef struct pa_envelope_item pa_envelope_item;
-
-typedef struct pa_envelope_def {
- unsigned n_points;
-
- pa_usec_t points_x[PA_ENVELOPE_POINTS_MAX];
- struct {
- int32_t i[PA_ENVELOPE_POINTS_MAX];
- float f[PA_ENVELOPE_POINTS_MAX];
- } points_y;
-} pa_envelope_def;
-
-pa_envelope *pa_envelope_new(const pa_sample_spec *ss);
-void pa_envelope_free(pa_envelope *e);
-pa_envelope_item *pa_envelope_add(pa_envelope *e, const pa_envelope_def *def);
-pa_envelope_item *pa_envelope_replace(pa_envelope *e, pa_envelope_item *i, const pa_envelope_def *def);
-void pa_envelope_remove(pa_envelope *e, pa_envelope_item *i);
-void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk);
-void pa_envelope_rewind(pa_envelope *e, size_t n_bytes);
-void pa_envelope_restart(pa_envelope* e);
-pa_bool_t pa_envelope_is_finished(pa_envelope* e);
-int32_t pa_envelope_length(pa_envelope *e);
-
-#endif
diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c
index 3930ba61..5455d0e8 100644
--- a/src/pulsecore/ipacl.c
+++ b/src/pulsecore/ipacl.c
@@ -169,7 +169,7 @@ void pa_ip_acl_free(pa_ip_acl *acl) {
int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
struct sockaddr_storage sa;
struct acl_entry *e;
- socklen_t salen;
+ socklen_t salen;
pa_assert(acl);
pa_assert(fd >= 0);
@@ -206,7 +206,7 @@ int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
return 1;
#ifdef HAVE_IPV6
} else if (e->family == AF_INET6) {
- int i, bits ;
+ int i, bits;
struct sockaddr_in6 *sai = (struct sockaddr_in6*) &sa;
if (e->bits == 128)
diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c
index 2c0e267a..b12cbf0c 100644
--- a/src/pulsecore/log.c
+++ b/src/pulsecore/log.c
@@ -70,6 +70,7 @@ static pa_log_level_t maximum_level = PA_LOG_ERROR, maximum_level_override = PA_
static unsigned show_backtrace = 0, show_backtrace_override = 0, skip_backtrace = 0;
static pa_log_flags_t flags = 0, flags_override = 0;
static pa_bool_t no_rate_limit = FALSE;
+static int log_fd = -1;
#ifdef HAVE_SYSLOG_H
static const int level_to_syslog[] = {
@@ -128,6 +129,15 @@ void pa_log_set_flags(pa_log_flags_t _flags, pa_log_merge_t merge) {
flags = _flags;
}
+void pa_log_set_fd(int fd) {
+ if (fd >= 0)
+ log_fd = fd;
+ else if (log_fd >= 0) {
+ pa_close(log_fd);
+ log_fd = -1;
+ }
+}
+
void pa_log_set_show_backtrace(unsigned nlevels) {
show_backtrace = nlevels;
}
@@ -399,6 +409,23 @@ void pa_log_levelv_meta(
}
#endif
+ case PA_LOG_FD: {
+ if (log_fd >= 0) {
+ char metadata[256];
+
+ pa_snprintf(metadata, sizeof(metadata), "\n%c %s %s", level_to_char[level], timestamp, location);
+
+ if ((write(log_fd, metadata, strlen(metadata)) < 0) || (write(log_fd, t, strlen(t)) < 0)) {
+ saved_errno = errno;
+ pa_log_set_fd(-1);
+ fprintf(stderr, "%s\n", "Error writing logs to a file descriptor. Redirect log messages to console.");
+ fprintf(stderr, "%s %s\n", metadata, t);
+ pa_log_set_target(PA_LOG_STDERR);
+ }
+ }
+
+ break;
+ }
case PA_LOG_NULL:
default:
break;
diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h
index 1fd38d44..ad04e7bd 100644
--- a/src/pulsecore/log.h
+++ b/src/pulsecore/log.h
@@ -36,6 +36,7 @@ typedef enum pa_log_target {
PA_LOG_STDERR, /* default */
PA_LOG_SYSLOG,
PA_LOG_NULL, /* to /dev/null */
+ PA_LOG_FD, /* to a file descriptor, e.g. a char device */
PA_LOG_TARGET_MAX
} pa_log_target_t;
@@ -74,6 +75,10 @@ void pa_log_set_level(pa_log_level_t l);
/* Set flags */
void pa_log_set_flags(pa_log_flags_t flags, pa_log_merge_t merge);
+/* Set the file descriptor of the logging device.
+ Daemon conf is in charge of opening this device */
+void pa_log_set_fd(int fd);
+
/* Enable backtrace */
void pa_log_set_show_backtrace(unsigned nlevels);
diff --git a/src/pulsecore/ltdl-helper.c b/src/pulsecore/ltdl-helper.c
index be200ca2..1a0e5558 100644
--- a/src/pulsecore/ltdl-helper.c
+++ b/src/pulsecore/ltdl-helper.c
@@ -42,7 +42,7 @@ pa_void_func_t pa_load_sym(lt_dlhandle handle, const char *module, const char *s
pa_assert(handle);
pa_assert(symbol);
- *(void**) &f = lt_dlsym(handle, symbol);
+ f = (pa_void_func_t) lt_dlsym(handle, symbol);
if (f)
return f;
@@ -59,7 +59,7 @@ pa_void_func_t pa_load_sym(lt_dlhandle handle, const char *module, const char *s
if (!isalnum(*c))
*c = '_';
- *(void**) &f = lt_dlsym(handle, sn);
+ f = (pa_void_func_t) lt_dlsym(handle, sn);
pa_xfree(sn);
return f;
diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c
index 454900d1..bc804577 100644
--- a/src/pulsecore/memblock.c
+++ b/src/pulsecore/memblock.c
@@ -82,7 +82,7 @@ struct pa_memblock {
pa_free_cb_t free_cb;
} user;
- struct {
+ struct {
uint32_t id;
pa_memimport_segment *segment;
} imported;
@@ -531,9 +531,7 @@ static void memblock_free(pa_memblock *b) {
pa_mutex_lock(import->mutex);
- pa_assert_se(pa_hashmap_remove(
- import->blocks,
- PA_UINT32_TO_PTR(b->per_type.imported.id)));
+ pa_assert_se(pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)));
pa_assert(segment->n_blocks >= 1);
if (-- segment->n_blocks <= 0)
@@ -693,9 +691,7 @@ static void memblock_replace_import(pa_memblock *b) {
pa_mutex_lock(import->mutex);
- pa_assert_se(pa_hashmap_remove(
- import->blocks,
- PA_UINT32_TO_PTR(b->per_type.imported.id)));
+ pa_assert_se(pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)));
memblock_make_local(b);
diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c
index 11faedac..c76ca841 100644
--- a/src/pulsecore/memblockq.c
+++ b/src/pulsecore/memblockq.c
@@ -376,8 +376,8 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
size_t d;
pa_assert(bq->write_index + (int64_t)chunk.length > q->index &&
- bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length &&
- bq->write_index < q->index);
+ bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length &&
+ bq->write_index < q->index);
/* The job overwrites the current entry at the end, so let's drop the beginning of this entry */
diff --git a/src/pulsecore/memtrap.c b/src/pulsecore/memtrap.c
index b56d806a..4df1fb71 100644
--- a/src/pulsecore/memtrap.c
+++ b/src/pulsecore/memtrap.c
@@ -67,11 +67,11 @@ pa_bool_t pa_memtrap_is_good(pa_memtrap *m) {
return !pa_atomic_load(&m->bad);
}
+#ifdef HAVE_SIGACTION
static void sigsafe_error(const char *s) {
(void) write(STDERR_FILENO, s, strlen(s));
}
-#ifdef HAVE_SIGACTION
static void signal_handler(int sig, siginfo_t* si, void *data) {
unsigned j;
pa_memtrap *m;
diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c
index e78cdb9a..3106775f 100644
--- a/src/pulsecore/modargs.c
+++ b/src/pulsecore/modargs.c
@@ -124,7 +124,7 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) {
key_len++;
break;
- case VALUE_START:
+ case VALUE_START:
if (*p == '\'') {
state = VALUE_TICKS;
value = p+1;
diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c
index 74e94da4..1b1e1126 100644
--- a/src/pulsecore/module.c
+++ b/src/pulsecore/module.c
@@ -110,7 +110,7 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
m->unload_requested = FALSE;
if (m->init(m) < 0) {
- pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : "");
+ pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : "");
goto fail;
}
diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c
index 0d6da3ee..f075a5bf 100644
--- a/src/pulsecore/play-memblockq.c
+++ b/src/pulsecore/play-memblockq.c
@@ -135,6 +135,12 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
return -1;
}
+ /* FIXME: u->memblockq doesn't have a silence memchunk set, so
+ * pa_memblockq_peek() will return 0 without returning any memblock if the
+ * read index points to a hole. If the memblockq is rewound beyond index 0,
+ * then there will be a hole. */
+ pa_assert(chunk->memblock);
+
chunk->length = PA_MIN(chunk->length, nbytes);
pa_memblockq_drop(u->memblockq, chunk->length);
diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c
index b993c478..df4feb01 100644
--- a/src/pulsecore/poll.c
+++ b/src/pulsecore/poll.c
@@ -105,7 +105,7 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
- ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
+ ready = select((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
@@ -160,7 +160,7 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
/* Linux alters the tv struct... but it shouldn't matter here ...
* as we're going to be a little bit out anyway as we've just eaten
* more than a couple of cpu cycles above */
- ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
+ ready = select((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
}
diff --git a/src/pulsecore/poll.h b/src/pulsecore/poll.h
index a137d974..dc741e5e 100644
--- a/src/pulsecore/poll.h
+++ b/src/pulsecore/poll.h
@@ -43,12 +43,11 @@
#define POLLNVAL 0x020 /* Invalid polling request. */
/* Data structure describing a polling request. */
-struct pollfd
- {
+struct pollfd {
int fd; /* File descriptor to poll. */
short int events; /* Types of events poller cares about. */
short int revents; /* Types of events that actually occurred. */
- };
+};
/* Poll the file descriptors described by the NFDS structures starting at
@@ -62,5 +61,5 @@ struct pollfd
#if defined(HAVE_POLL_H) && !defined(OS_IS_DARWIN)
#define pa_poll(fds,nfds,timeout) poll((fds),(nfds),(timeout))
#else
-int pa_poll (struct pollfd *fds, unsigned long nfds, int timeout);
+int pa_poll(struct pollfd *fds, unsigned long nfds, int timeout);
#endif
diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c
index 045c5c95..66fd73c8 100644
--- a/src/pulsecore/protocol-esound.c
+++ b/src/pulsecore/protocol-esound.c
@@ -55,8 +55,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/thread-mq.h>
#include <pulsecore/shared.h>
-
-#include "endianmacros.h"
+#include <pulsecore/endianmacros.h>
#include "protocol-esound.h"
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index cc6a6b1d..bb4be726 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -1293,7 +1293,7 @@ static void native_connection_send_memblock(pa_native_connection *c) {
else if (start == c->rrobin_index)
return;
- if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
+ if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
pa_memchunk schunk = chunk;
if (schunk.length > r->buffer_attr.fragsize)
@@ -1387,7 +1387,7 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
/* If more data is in queue, we rewind later instead. */
if (s->seek_windex != -1)
- windex = PA_MIN(windex, s->seek_windex);
+ windex = PA_MIN(windex, s->seek_windex);
if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
s->seek_windex = windex;
else {
@@ -1406,7 +1406,7 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
pa_sink_input *isync;
void (*func)(pa_memblockq *bq);
- switch (code) {
+ switch (code) {
case SINK_INPUT_MESSAGE_FLUSH:
func = flush_write_no_account;
break;
@@ -1918,7 +1918,7 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
if (name)
pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
- if (c->version >= 12) {
+ if (c->version >= 12) {
/* Since 0.9.8 the user can ask for a couple of additional flags */
if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
@@ -2009,14 +2009,14 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
}
flags =
- (corked ? PA_SINK_INPUT_START_CORKED : 0) |
- (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
- (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
- (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
- (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
- (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
- (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
- (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
+ (corked ? PA_SINK_INPUT_START_CORKED : 0) |
+ (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
+ (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
+ (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
+ (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
+ (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
+ (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
+ (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
(dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
(fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
(passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0);
@@ -2185,7 +2185,7 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
if (name)
pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
- if (c->version >= 12) {
+ if (c->version >= 12) {
/* Since 0.9.8 the user can ask for a couple of additional flags */
if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
@@ -2266,14 +2266,14 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
}
flags =
- (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
- (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
- (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
- (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
- (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
- (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
- (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
- (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
+ (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
+ (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
+ (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
+ (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
+ (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
+ (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
+ (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
+ (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
(dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
(fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0);
@@ -2902,7 +2902,7 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin
PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
PA_TAG_USEC, pa_sink_get_latency(sink),
PA_TAG_STRING, sink->driver,
- PA_TAG_U32, sink->flags,
+ PA_TAG_U32, sink->flags & ~PA_SINK_SHARE_VOLUME_WITH_MASTER,
PA_TAG_INVALID);
if (c->version >= 13) {
@@ -3056,12 +3056,19 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t,
pa_sample_spec fixed_ss;
pa_usec_t sink_latency;
pa_cvolume v;
+ pa_bool_t has_volume = FALSE;
pa_assert(t);
pa_sink_input_assert_ref(s);
fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
+ has_volume = pa_sink_input_is_volume_readable(s);
+ if (has_volume)
+ pa_sink_input_get_volume(s, &v, TRUE);
+ else
+ pa_cvolume_reset(&v, fixed_ss.channels);
+
pa_tagstruct_putu32(t, s->index);
pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
@@ -3069,7 +3076,7 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t,
pa_tagstruct_putu32(t, s->sink->index);
pa_tagstruct_put_sample_spec(t, &fixed_ss);
pa_tagstruct_put_channel_map(t, &s->channel_map);
- pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s, &v, TRUE));
+ pa_tagstruct_put_cvolume(t, &v);
pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
pa_tagstruct_put_usec(t, sink_latency);
pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
@@ -3080,6 +3087,10 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t,
pa_tagstruct_put_proplist(t, s->proplist);
if (c->version >= 19)
pa_tagstruct_put_boolean(t, (pa_sink_input_get_state(s) == PA_SINK_INPUT_CORKED));
+ if (c->version >= 20) {
+ pa_tagstruct_put_boolean(t, has_volume);
+ pa_tagstruct_put_boolean(t, has_volume ? !pa_sink_input_is_volume_writable(s) : FALSE);
+ }
}
static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
@@ -3461,6 +3472,7 @@ static void command_set_volume(
pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
pa_source_set_volume(source, &volume, TRUE);
} else if (si) {
+ CHECK_VALIDITY(c->pstream, pa_sink_input_is_volume_writable(si), tag, PA_ERR_INVALID);
CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
pa_log_debug("Client %s changes volume of sink input %s.",
@@ -4927,7 +4939,7 @@ pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
}
pa_client* pa_native_connection_get_client(pa_native_connection *c) {
- pa_native_connection_assert_ref(c);
+ pa_native_connection_assert_ref(c);
- return c->client;
+ return c->client;
}
diff --git a/src/pulsecore/remap.c b/src/pulsecore/remap.c
index a0fc85b9..b831f78c 100644
--- a/src/pulsecore/remap.c
+++ b/src/pulsecore/remap.c
@@ -32,7 +32,7 @@
#include "remap.h"
-static void remap_mono_to_stereo_c (pa_remap_t *m, void *dst, const void *src, unsigned n) {
+static void remap_mono_to_stereo_c(pa_remap_t *m, void *dst, const void *src, unsigned n) {
unsigned i;
switch (*m->format) {
@@ -85,7 +85,7 @@ static void remap_mono_to_stereo_c (pa_remap_t *m, void *dst, const void *src, u
}
}
-static void remap_channels_matrix_c (pa_remap_t *m, void *dst, const void *src, unsigned n) {
+static void remap_channels_matrix_c(pa_remap_t *m, void *dst, const void *src, unsigned n) {
unsigned oc, ic, i;
unsigned n_ic, n_oc;
@@ -97,7 +97,7 @@ static void remap_channels_matrix_c (pa_remap_t *m, void *dst, const void *src,
{
float *d, *s;
- memset(dst, 0, n * sizeof (float) * n_oc);
+ memset(dst, 0, n * sizeof(float) * n_oc);
for (oc = 0; oc < n_oc; oc++) {
@@ -128,7 +128,7 @@ static void remap_channels_matrix_c (pa_remap_t *m, void *dst, const void *src,
{
int16_t *d, *s;
- memset(dst, 0, n * sizeof (int16_t) * n_oc);
+ memset(dst, 0, n * sizeof(int16_t) * n_oc);
for (oc = 0; oc < n_oc; oc++) {
@@ -160,7 +160,7 @@ static void remap_channels_matrix_c (pa_remap_t *m, void *dst, const void *src,
}
/* set the function that will execute the remapping based on the matrices */
-static void init_remap_c (pa_remap_t *m) {
+static void init_remap_c(pa_remap_t *m) {
unsigned n_oc, n_ic;
n_oc = m->o_ss->channels;
@@ -181,17 +181,17 @@ static void init_remap_c (pa_remap_t *m) {
/* default C implementation */
static pa_init_remap_func_t remap_func = init_remap_c;
-void pa_init_remap (pa_remap_t *m) {
- pa_assert (remap_func);
+void pa_init_remap(pa_remap_t *m) {
+ pa_assert(remap_func);
m->do_remap = NULL;
/* call the installed remap init function */
- remap_func (m);
+ remap_func(m);
if (m->do_remap == NULL) {
/* nothing was installed, fallback to C version */
- init_remap_c (m);
+ init_remap_c(m);
}
}
diff --git a/src/pulsecore/remap_mmx.c b/src/pulsecore/remap_mmx.c
index d358a58b..37d72da7 100644
--- a/src/pulsecore/remap_mmx.c
+++ b/src/pulsecore/remap_mmx.c
@@ -103,7 +103,7 @@
" emms \n\t"
#if defined (__i386__) || defined (__amd64__)
-static void remap_mono_to_stereo_mmx (pa_remap_t *m, void *dst, const void *src, unsigned n) {
+static void remap_mono_to_stereo_mmx(pa_remap_t *m, void *dst, const void *src, unsigned n) {
pa_reg_x86 temp, temp2;
switch (*m->format) {
@@ -133,7 +133,7 @@ static void remap_mono_to_stereo_mmx (pa_remap_t *m, void *dst, const void *src,
}
/* set the function that will execute the remapping based on the matrices */
-static void init_remap_mmx (pa_remap_t *m) {
+static void init_remap_mmx(pa_remap_t *m) {
unsigned n_oc, n_ic;
n_oc = m->o_ss->channels;
@@ -148,13 +148,13 @@ static void init_remap_mmx (pa_remap_t *m) {
}
#endif /* defined (__i386__) || defined (__amd64__) */
-void pa_remap_func_init_mmx (pa_cpu_x86_flag_t flags) {
+void pa_remap_func_init_mmx(pa_cpu_x86_flag_t flags) {
#if defined (__i386__) || defined (__amd64__)
if (flags & PA_CPU_X86_MMX) {
pa_log_info("Initialising MMX optimized remappers.");
- pa_set_init_remap_func ((pa_init_remap_func_t) init_remap_mmx);
+ pa_set_init_remap_func((pa_init_remap_func_t) init_remap_mmx);
}
#endif /* defined (__i386__) || defined (__amd64__) */
diff --git a/src/pulsecore/remap_sse.c b/src/pulsecore/remap_sse.c
index 0ccf3161..e1cb161d 100644
--- a/src/pulsecore/remap_sse.c
+++ b/src/pulsecore/remap_sse.c
@@ -102,7 +102,7 @@
"4: \n\t"
#if defined (__i386__) || defined (__amd64__)
-static void remap_mono_to_stereo_sse2 (pa_remap_t *m, void *dst, const void *src, unsigned n) {
+static void remap_mono_to_stereo_sse2(pa_remap_t *m, void *dst, const void *src, unsigned n) {
pa_reg_x86 temp, temp2;
switch (*m->format) {
@@ -132,7 +132,7 @@ static void remap_mono_to_stereo_sse2 (pa_remap_t *m, void *dst, const void *src
}
/* set the function that will execute the remapping based on the matrices */
-static void init_remap_sse2 (pa_remap_t *m) {
+static void init_remap_sse2(pa_remap_t *m) {
unsigned n_oc, n_ic;
n_oc = m->o_ss->channels;
@@ -147,7 +147,7 @@ static void init_remap_sse2 (pa_remap_t *m) {
}
#endif /* defined (__i386__) || defined (__amd64__) */
-void pa_remap_func_init_sse (pa_cpu_x86_flag_t flags) {
+void pa_remap_func_init_sse(pa_cpu_x86_flag_t flags) {
#if defined (__i386__) || defined (__amd64__)
if (flags & PA_CPU_X86_SSE2) {
diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index bed5a20d..b5c1611c 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -36,11 +36,11 @@
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/strbuf.h>
+#include <pulsecore/remap.h>
#include "ffmpeg/avcodec.h"
#include "resampler.h"
-#include "remap.h"
/* Number of samples of extra space we allow the resamplers to return */
#define EXTRA_FRAMES 128
@@ -898,7 +898,7 @@ static void calc_map_table(pa_resampler *r) {
if (!on_center(r->o_cm.map[oc]))
continue;
- for (ic = 0; ic < n_ic; ic++) {
+ for (ic = 0; ic < n_ic; ic++) {
if (ic_connected[ic]) {
m->map_table_f[oc][ic] *= .9f;
@@ -961,7 +961,7 @@ static void calc_map_table(pa_resampler *r) {
if (ncenter[oc] <= 0)
continue;
- for (ic = 0; ic < n_ic; ic++) {
+ for (ic = 0; ic < n_ic; ic++) {
if (ic_connected[ic]) {
m->map_table_f[oc][ic] *= .75f;
@@ -983,7 +983,7 @@ static void calc_map_table(pa_resampler *r) {
/* OK, so there is an unconnected LFE channel. Let's mix
* it into all channels, with factor 0.375 */
- for (ic = 0; ic < n_ic; ic++) {
+ for (ic = 0; ic < n_ic; ic++) {
if (!on_lfe(r->i_cm.map[ic]))
continue;
@@ -1022,7 +1022,7 @@ static void calc_map_table(pa_resampler *r) {
pa_xfree(t);
/* initialize the remapping function */
- pa_init_remap (m);
+ pa_init_remap(m);
}
static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) {
@@ -1096,8 +1096,8 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
remap = &r->remap;
- pa_assert (remap->do_remap);
- remap->do_remap (remap, dst, src, n_frames);
+ pa_assert(remap->do_remap);
+ remap->do_remap(remap, dst, src, n_frames);
pa_memblock_release(input->memblock);
pa_memblock_release(r->buf2.memblock);
diff --git a/src/pulsecore/rtpoll.c b/src/pulsecore/rtpoll.c
index 98d7d625..a5e990f6 100644
--- a/src/pulsecore/rtpoll.c
+++ b/src/pulsecore/rtpoll.c
@@ -124,7 +124,7 @@ static void rtpoll_rebuild(pa_rtpoll *p) {
for (i = p->items; i; i = i->next) {
- if (i->n_pollfd > 0) {
+ if (i->n_pollfd > 0) {
size_t l = i->n_pollfd * sizeof(struct pollfd);
if (i->pollfd)
diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c
index 74600dec..62b7c468 100644
--- a/src/pulsecore/sample-util.c
+++ b/src/pulsecore/sample-util.c
@@ -37,9 +37,9 @@
#include <pulsecore/macro.h>
#include <pulsecore/g711.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/endianmacros.h>
#include "sample-util.h"
-#include "endianmacros.h"
#define PA_SILENCE_MAX (PA_PAGE_SIZE*16)
@@ -752,7 +752,7 @@ void pa_volume_memchunk(
return;
}
- do_volume = pa_get_volume_func (spec->format);
+ do_volume = pa_get_volume_func(spec->format);
pa_assert(do_volume);
calc_volume_table[spec->format] ((void *)linear, volume);
diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c
index 0fefdf1c..43587f3e 100644
--- a/src/pulsecore/sconv-s16le.c
+++ b/src/pulsecore/sconv-s16le.c
@@ -31,8 +31,7 @@
#include <pulsecore/sconv.h>
#include <pulsecore/macro.h>
#include <pulsecore/log.h>
-
-#include "endianmacros.h"
+#include <pulsecore/endianmacros.h>
#include "sconv-s16le.h"
diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c
index 301f08b4..988d4b33 100644
--- a/src/pulsecore/sconv.c
+++ b/src/pulsecore/sconv.c
@@ -29,10 +29,10 @@
#include <pulsecore/g711.h>
#include <pulsecore/macro.h>
+#include <pulsecore/endianmacros.h>
-#include "endianmacros.h"
-#include "sconv-s16le.h"
-#include "sconv-s16be.h"
+#include <pulsecore/sconv-s16le.h>
+#include <pulsecore/sconv-s16be.h>
#include "sconv.h"
diff --git a/src/pulsecore/sconv_sse.c b/src/pulsecore/sconv_sse.c
index 3737af2a..26daa223 100644
--- a/src/pulsecore/sconv_sse.c
+++ b/src/pulsecore/sconv_sse.c
@@ -29,13 +29,12 @@
#include <pulsecore/g711.h>
#include <pulsecore/macro.h>
-
-#include "endianmacros.h"
+#include <pulsecore/endianmacros.h>
#include "cpu-x86.h"
#include "sconv.h"
-#if defined (__i386__) || defined (__amd64__)
+#if !defined(__APPLE__) && defined (__i386__) || defined (__amd64__)
static const PA_DECLARE_ALIGNED (16, float, one[4]) = { 1.0, 1.0, 1.0, 1.0 };
static const PA_DECLARE_ALIGNED (16, float, mone[4]) = { -1.0, -1.0, -1.0, -1.0 };
@@ -170,7 +169,7 @@ static void pa_sconv_s16le_from_f32ne_sse2(unsigned n, const float *a, int16_t *
#define SAMPLES 1019
#define TIMES 1000
-static void run_test (void) {
+static void run_test(void) {
int16_t samples[SAMPLES];
int16_t samples_ref[SAMPLES];
float floats[SAMPLES];
@@ -178,18 +177,18 @@ static void run_test (void) {
pa_usec_t start, stop;
pa_convert_func_t func;
- printf ("checking SSE %zd\n", sizeof (samples));
+ printf("checking SSE %zd\n", sizeof(samples));
- memset (samples_ref, 0, sizeof (samples_ref));
- memset (samples, 0, sizeof (samples));
+ memset(samples_ref, 0, sizeof(samples_ref));
+ memset(samples, 0, sizeof(samples));
for (i = 0; i < SAMPLES; i++) {
floats[i] = (rand()/(RAND_MAX+2.2)) - 1.1;
}
- func = pa_get_convert_from_float32ne_function (PA_SAMPLE_S16LE);
- func (SAMPLES, floats, samples_ref);
- pa_sconv_s16le_from_f32ne_sse2 (SAMPLES, floats, samples);
+ func = pa_get_convert_from_float32ne_function(PA_SAMPLE_S16LE);
+ func(SAMPLES, floats, samples_ref);
+ pa_sconv_s16le_from_f32ne_sse2(SAMPLES, floats, samples);
for (i = 0; i < SAMPLES; i++) {
if (samples[i] != samples_ref[i]) {
@@ -200,14 +199,14 @@ static void run_test (void) {
start = pa_rtclock_now();
for (i = 0; i < TIMES; i++) {
- pa_sconv_s16le_from_f32ne_sse2 (SAMPLES, floats, samples);
+ pa_sconv_s16le_from_f32ne_sse2(SAMPLES, floats, samples);
}
stop = pa_rtclock_now();
pa_log_info("SSE: %llu usec.", (long long unsigned int)(stop - start));
start = pa_rtclock_now();
for (i = 0; i < TIMES; i++) {
- func (SAMPLES, floats, samples_ref);
+ func(SAMPLES, floats, samples_ref);
}
stop = pa_rtclock_now();
pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start));
@@ -216,19 +215,19 @@ static void run_test (void) {
#endif /* defined (__i386__) || defined (__amd64__) */
-void pa_convert_func_init_sse (pa_cpu_x86_flag_t flags) {
-#if defined (__i386__) || defined (__amd64__)
+void pa_convert_func_init_sse(pa_cpu_x86_flag_t flags) {
+#if !defined(__APPLE__) && defined (__i386__) || defined (__amd64__)
#ifdef RUN_TEST
- run_test ();
+ run_test();
#endif
if (flags & PA_CPU_X86_SSE2) {
pa_log_info("Initialising SSE2 optimized conversions.");
- pa_set_convert_from_float32ne_function (PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse2);
+ pa_set_convert_from_float32ne_function(PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse2);
} else {
pa_log_info("Initialising SSE optimized conversions.");
- pa_set_convert_from_float32ne_function (PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse);
+ pa_set_convert_from_float32ne_function(PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse);
}
#endif /* defined (__i386__) || defined (__amd64__) */
diff --git a/src/pulsecore/semaphore-osx.c b/src/pulsecore/semaphore-osx.c
index 73f43559..42afd154 100644
--- a/src/pulsecore/semaphore-osx.c
+++ b/src/pulsecore/semaphore-osx.c
@@ -30,8 +30,7 @@
#include "semaphore.h"
-struct pa_semaphore
-{
+struct pa_semaphore {
MPSemaphoreID sema;
};
diff --git a/src/pulsecore/semaphore-win32.c b/src/pulsecore/semaphore-win32.c
index 9ffbde66..c2e00c63 100644
--- a/src/pulsecore/semaphore-win32.c
+++ b/src/pulsecore/semaphore-win32.c
@@ -30,8 +30,7 @@
#include "semaphore.h"
-struct pa_semaphore
-{
+struct pa_semaphore {
HANDLE sema;
};
diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c
index 5d5d85ab..da8aff70 100644
--- a/src/pulsecore/shm.c
+++ b/src/pulsecore/shm.c
@@ -90,10 +90,12 @@ struct shm_marker {
#define SHM_MARKER_SIZE PA_ALIGN(sizeof(struct shm_marker))
+#ifdef HAVE_SHM_OPEN
static char *segment_name(char *fn, size_t l, unsigned id) {
pa_snprintf(fn, l, "/pulse-shm-%u", id);
return fn;
}
+#endif
int pa_shm_create_rw(pa_shm *m, size_t size, pa_bool_t shared, mode_t mode) {
char fn[32];
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 065fd2d3..e0e81be4 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -38,7 +38,6 @@
#include <pulsecore/play-memblockq.h>
#include <pulsecore/namereg.h>
#include <pulsecore/core-util.h>
-#include <pulse/timeval.h>
#include "sink-input.h"
@@ -49,11 +48,6 @@ PA_DEFINE_PUBLIC_CLASS(pa_sink_input, pa_msgobject);
static void sink_input_free(pa_object *o);
static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v);
-static void sink_input_set_ramping_info(pa_sink_input* i, pa_volume_t pre_virtual_volume, pa_volume_t target_virtual_volume, pa_usec_t t);
-static void sink_input_set_ramping_info_for_mute(pa_sink_input* i, pa_bool_t mute, pa_usec_t t);
-static void sink_input_volume_ramping(pa_sink_input* i, pa_memchunk* chunk);
-static void sink_input_rewind_ramp_info(pa_sink_input *i, size_t nbytes);
-static void sink_input_release_envelope(pa_sink_input *i);
static int check_passthrough_connection(pa_sink_input_flags_t flags, pa_sink *dest) {
@@ -80,10 +74,10 @@ static int check_passthrough_connection(pa_sink_input_flags_t flags, pa_sink *de
}
} else {
- if (flags & PA_SINK_INPUT_PASSTHROUGH) {
- pa_log_warn("Cannot connect PASSTHROUGH sink input to sink without PASSTHROUGH capabilities");
- return -PA_ERR_INVALID;
- }
+ if (flags & PA_SINK_INPUT_PASSTHROUGH) {
+ pa_log_warn("Cannot connect PASSTHROUGH sink input to sink without PASSTHROUGH capabilities");
+ return -PA_ERR_INVALID;
+ }
}
return PA_OK;
}
@@ -112,8 +106,21 @@ void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const
data->channel_map = *map;
}
+pa_bool_t pa_sink_input_new_data_is_volume_writable(pa_sink_input_new_data *data) {
+ pa_assert(data);
+
+ if (data->flags & PA_SINK_INPUT_PASSTHROUGH)
+ return FALSE;
+
+ if (data->origin_sink && (data->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ return FALSE;
+
+ return TRUE;
+}
+
void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
pa_assert(data);
+ pa_assert(pa_sink_input_new_data_is_volume_writable(data));
if ((data->volume_is_set = !!volume))
data->volume = *volume;
@@ -205,6 +212,7 @@ int pa_sink_input_new(
if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data)) < 0)
return r;
+ pa_assert(!data->volume_is_set || pa_sink_input_new_data_is_volume_writable(data));
pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID);
if (!data->sink) {
@@ -321,6 +329,7 @@ int pa_sink_input_new(
i->driver = pa_xstrdup(pa_path_get_filename(data->driver));
i->module = data->module;
i->sink = data->sink;
+ i->origin_sink = data->origin_sink;
i->client = data->client;
i->requested_resample_method = data->resample_method;
@@ -328,7 +337,7 @@ int pa_sink_input_new(
i->sample_spec = data->sample_spec;
i->channel_map = data->channel_map;
- if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !data->volume_is_absolute) {
+ if (!data->volume_is_absolute && pa_sink_flat_volume_enabled(i->sink)) {
pa_cvolume remapped;
/* When the 'absolute' bool is not set then we'll treat the volume
@@ -365,16 +374,6 @@ int pa_sink_input_new(
reset_callbacks(i);
i->userdata = NULL;
- /* Set Ramping info */
- i->thread_info.ramp_info.is_ramping = FALSE;
- i->thread_info.ramp_info.envelope_dead = TRUE;
- i->thread_info.ramp_info.envelope = NULL;
- i->thread_info.ramp_info.item = NULL;
- i->thread_info.ramp_info.envelope_dying = 0;
-
- pa_atomic_store(&i->before_ramping_v, 0);
- pa_atomic_store(&i->before_ramping_m, 0);
-
i->thread_info.state = i->state;
i->thread_info.attached = FALSE;
pa_atomic_store(&i->thread_info.drained, 1);
@@ -481,7 +480,7 @@ static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state)
/* Called from main context */
void pa_sink_input_unlink(pa_sink_input *i) {
pa_bool_t linked;
- pa_source_output *o, *p = NULL;
+ pa_source_output *o, *p = NULL;
pa_assert(i);
pa_assert_ctl_context();
@@ -523,7 +522,7 @@ void pa_sink_input_unlink(pa_sink_input *i) {
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)
+ if (pa_sink_flat_volume_enabled(i->sink))
pa_sink_set_volume(i->sink, NULL, FALSE, FALSE);
if (i->sink->asyncmsgq)
@@ -565,12 +564,6 @@ static void sink_input_free(pa_object *o) {
* "half-moved" or are connected to sinks that have no asyncmsgq
* and are hence half-destructed themselves! */
- if (i->thread_info.ramp_info.envelope) {
- pa_log_debug ("Freeing envelope\n");
- pa_envelope_free(i->thread_info.ramp_info.envelope);
- i->thread_info.ramp_info.envelope = NULL;
- }
-
if (i->thread_info.render_memblockq)
pa_memblockq_free(i->thread_info.render_memblockq);
@@ -610,10 +603,16 @@ void pa_sink_input_put(pa_sink_input *i) {
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)
+ if (pa_sink_flat_volume_enabled(i->sink))
pa_sink_set_volume(i->sink, NULL, FALSE, i->save_volume);
- else
+ else {
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ pa_assert(pa_cvolume_is_norm(&i->volume));
+ pa_assert(pa_cvolume_is_norm(&i->reference_ratio));
+ }
+
set_real_ratio(i, &i->volume);
+ }
i->thread_info.soft_volume = i->soft_volume;
i->thread_info.muted = i->muted;
@@ -658,7 +657,6 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) {
void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa_memchunk *chunk, pa_cvolume *volume) {
pa_bool_t do_volume_adj_here, need_volume_factor_sink;
pa_bool_t volume_is_norm;
- pa_bool_t ramping;
size_t block_size_max_sink, block_size_max_sink_input;
size_t ilength;
@@ -703,7 +701,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p
* to adjust the volume *before* we resample. Otherwise we can do
* it after and leave it for the sink code */
- do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map) || i->thread_info.ramp_info.is_ramping;
+ 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.soft_volume) && !i->thread_info.muted;
need_volume_factor_sink = !pa_cvolume_is_norm(&i->volume_factor_sink);
@@ -746,7 +744,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p
wchunk.length = block_size_max_sink_input;
/* It might be necessary to adjust the volume here */
- if (do_volume_adj_here && !volume_is_norm && !i->thread_info.ramp_info.is_ramping) {
+ if (do_volume_adj_here && !volume_is_norm) {
pa_memchunk_make_writable(&wchunk, 0);
if (i->thread_info.muted) {
@@ -812,23 +810,6 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p
if (chunk->length > block_size_max_sink)
chunk->length = block_size_max_sink;
- ramping = i->thread_info.ramp_info.is_ramping;
- if (ramping)
- sink_input_volume_ramping(i, chunk);
-
- if (!i->thread_info.ramp_info.envelope_dead) {
- i->thread_info.ramp_info.envelope_dying += chunk->length;
- pa_log_debug("Envelope dying is %d, chunk length is %zu, dead thresholder is %lu\n", i->thread_info.ramp_info.envelope_dying,
- chunk->length,
- i->sink->thread_info.max_rewind + pa_envelope_length(i->thread_info.ramp_info.envelope));
-
- if (i->thread_info.ramp_info.envelope_dying >= (int32_t) (i->sink->thread_info.max_rewind + pa_envelope_length(i->thread_info.ramp_info.envelope))) {
- pa_log_debug("RELEASE Envelop");
- i->thread_info.ramp_info.envelope_dead = TRUE;
- sink_input_release_envelope(i);
- }
- }
-
/* Let's see if we had to apply the volume adjustment ourselves,
* or if this can be done by the sink for us */
@@ -873,7 +854,6 @@ void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sam
if (nbytes > 0 && !i->thread_info.dont_rewind_render) {
pa_log_debug("Have to rewind %lu bytes on render memblockq.", (unsigned long) nbytes);
pa_memblockq_rewind(i->thread_info.render_memblockq, nbytes);
- sink_input_rewind_ramp_info(i, nbytes);
}
if (i->thread_info.rewrite_nbytes == (size_t) -1) {
@@ -1010,7 +990,7 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec)
if (usec != (pa_usec_t) -1) {
pa_usec_t min_latency, max_latency;
pa_sink_get_latency_range(i->sink, &min_latency, &max_latency);
- usec = PA_CLAMP(usec, min_latency, max_latency);
+ usec = PA_CLAMP(usec, min_latency, max_latency);
}
}
@@ -1037,6 +1017,64 @@ 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_bool_t save, pa_bool_t absolute) {
+ pa_cvolume v;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert_ctl_context();
+ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
+ pa_assert(volume);
+ pa_assert(pa_cvolume_valid(volume));
+ pa_assert(volume->channels == 1 || pa_cvolume_compatible(volume, &i->sample_spec));
+ pa_assert(pa_sink_input_is_volume_writable(i));
+
+ if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
+ v = i->sink->reference_volume;
+ pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map);
+
+ if (pa_cvolume_compatible(volume, &i->sample_spec))
+ volume = pa_sw_cvolume_multiply(&v, &v, volume);
+ else
+ volume = pa_sw_cvolume_multiply_scalar(&v, &v, pa_cvolume_max(volume));
+ } else {
+ if (!pa_cvolume_compatible(volume, &i->sample_spec)) {
+ v = i->volume;
+ volume = pa_cvolume_scale(&v, pa_cvolume_max(volume));
+ }
+ }
+
+ if (pa_cvolume_equal(volume, &i->volume)) {
+ i->save_volume = i->save_volume || save;
+ return;
+ }
+
+ i->volume = *volume;
+ i->save_volume = save;
+
+ if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
+ /* We are in flat volume mode, so let's update all sink input
+ * volumes and update the flat volume of the sink */
+
+ pa_sink_set_volume(i->sink, NULL, TRUE, save);
+
+ } else {
+ /* OK, we are in normal volume mode. The volume only affects
+ * ourselves */
+ set_real_ratio(i, volume);
+
+ /* Copy the new soft_volume to the thread_info struct */
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
+ }
+
+ /* The volume changed, let's tell people so */
+ if (i->volume_changed)
+ i->volume_changed(i);
+
+ /* The virtual volume changed, let's tell people so */
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+}
+
+/* Called from main context */
static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) {
pa_sink_input_assert_ref(i);
pa_assert_ctl_context();
@@ -1058,14 +1096,25 @@ static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) {
}
/* Called from main context */
-void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute) {
+pa_bool_t pa_sink_input_is_volume_readable(pa_sink_input *i) {
+ pa_sink_input_assert_ref(i);
+ pa_assert_ctl_context();
+
+ return !(i->flags & PA_SINK_INPUT_PASSTHROUGH);
+}
+
+/* Called from main context */
+pa_bool_t pa_sink_input_is_volume_writable(pa_sink_input *i) {
+ pa_sink_input_assert_ref(i);
+ pa_assert_ctl_context();
- /* Do not allow for volume changes for non-audio types */
if (i->flags & PA_SINK_INPUT_PASSTHROUGH)
- return;
+ return FALSE;
+
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ return FALSE;
- /* test ramping -> return pa_sink_input_set_volume_with_ramping(i, volume, save, absolute, 2000 * PA_USEC_PER_MSEC); */
- return pa_sink_input_set_volume_with_ramping(i, volume, save, absolute, 0);
+ return TRUE;
}
/* Called from main context */
@@ -1073,8 +1122,9 @@ pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bo
pa_sink_input_assert_ref(i);
pa_assert_ctl_context();
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
+ pa_assert(pa_sink_input_is_volume_readable(i));
- if (absolute || !(i->sink->flags & PA_SINK_FLAT_VOLUME))
+ if (absolute || !pa_sink_flat_volume_enabled(i->sink))
*volume = i->volume;
else
*volume = i->reference_ratio;
@@ -1084,8 +1134,25 @@ pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bo
/* Called from main context */
void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) {
- /* test ramping -> return pa_sink_input_set_mute_with_ramping(i, mute, save, 2000 * PA_USEC_PER_MSEC); */
- return pa_sink_input_set_mute_with_ramping(i, mute, save, 0);
+ pa_sink_input_assert_ref(i);
+ pa_assert_ctl_context();
+ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
+
+ if (!i->muted == !mute) {
+ i->save_muted = i->save_muted || mute;
+ return;
+ }
+
+ i->muted = mute;
+ i->save_muted = save;
+
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE, NULL, 0, NULL) == 0);
+
+ /* The mute status changed, let's tell people so */
+ if (i->mute_changed)
+ i->mute_changed(i);
+
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
}
/* Called from main context */
@@ -1245,7 +1312,7 @@ int pa_sink_input_start_move(pa_sink_input *i) {
if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED)
pa_assert_se(i->sink->n_corked-- >= 1);
- if (i->sink->flags & PA_SINK_FLAT_VOLUME)
+ if (pa_sink_flat_volume_enabled(i->sink))
/* We might need to update the sink's volume if we are in flat
* volume mode. */
pa_sink_set_volume(i->sink, NULL, FALSE, FALSE);
@@ -1261,6 +1328,156 @@ int pa_sink_input_start_move(pa_sink_input *i) {
return 0;
}
+/* Called from main context. If i has an origin sink that uses volume sharing,
+ * then also the origin sink and all streams connected to it need to update
+ * their volume - this function does all that by using recursion. */
+static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
+ pa_cvolume old_volume;
+
+ pa_assert(i);
+ pa_assert(dest);
+ pa_assert(i->sink); /* The destination sink should already be set. */
+
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ pa_sink *root_sink = i->sink;
+ pa_sink_input *origin_sink_input;
+ uint32_t idx;
+
+ while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+ root_sink = root_sink->input_to_master->sink;
+
+ if (pa_sink_flat_volume_enabled(i->sink)) {
+ /* Ok, so the origin sink uses volume sharing, and flat volume is
+ * enabled. The volume will have to be updated as follows:
+ *
+ * i->volume := i->sink->real_volume
+ * (handled later by pa_sink_set_volume)
+ * i->reference_ratio := i->volume / i->sink->reference_volume
+ * (handled later by pa_sink_set_volume)
+ * i->real_ratio stays unchanged
+ * (streams whose origin sink uses volume sharing should
+ * always have real_ratio of 0 dB)
+ * i->soft_volume stays unchanged
+ * (streams whose origin sink uses volume sharing should
+ * always have volume_factor as soft_volume, so no change
+ * should be needed) */
+
+ pa_assert(pa_cvolume_is_norm(&i->real_ratio));
+ pa_assert(pa_cvolume_equal(&i->soft_volume, &i->volume_factor));
+
+ /* Notifications will be sent by pa_sink_set_volume(). */
+
+ } else {
+ /* Ok, so the origin sink uses volume sharing, and flat volume is
+ * disabled. The volume will have to be updated as follows:
+ *
+ * i->volume := 0 dB
+ * i->reference_ratio := 0 dB
+ * i->real_ratio stays unchanged
+ * (streams whose origin sink uses volume sharing should
+ * always have real_ratio of 0 dB)
+ * i->soft_volume stays unchanged
+ * (streams whose origin sink uses volume sharing should
+ * always have volume_factor as soft_volume, so no change
+ * should be needed) */
+
+ old_volume = i->volume;
+ pa_cvolume_reset(&i->volume, i->volume.channels);
+ pa_cvolume_reset(&i->reference_ratio, i->reference_ratio.channels);
+ pa_assert(pa_cvolume_is_norm(&i->real_ratio));
+ pa_assert(pa_cvolume_equal(&i->soft_volume, &i->volume_factor));
+
+ /* Notify others about the changed sink input volume. */
+ if (!pa_cvolume_equal(&i->volume, &old_volume)) {
+ if (i->volume_changed)
+ i->volume_changed(i);
+
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
+ }
+
+ /* Additionally, the origin sink volume needs updating:
+ *
+ * i->origin_sink->reference_volume := root_sink->reference_volume
+ * i->origin_sink->real_volume := root_sink->real_volume
+ * i->origin_sink->soft_volume stays unchanged
+ * (sinks that use volume sharing should always have
+ * soft_volume of 0 dB) */
+
+ old_volume = i->origin_sink->reference_volume;
+
+ i->origin_sink->reference_volume = root_sink->reference_volume;
+ pa_cvolume_remap(&i->origin_sink->reference_volume, &root_sink->channel_map, &i->origin_sink->channel_map);
+
+ i->origin_sink->real_volume = root_sink->real_volume;
+ pa_cvolume_remap(&i->origin_sink->real_volume, &root_sink->channel_map, &i->origin_sink->channel_map);
+
+ pa_assert(pa_cvolume_is_norm(&i->origin_sink->soft_volume));
+
+ /* Notify others about the changed sink volume. If you wonder whether
+ * i->origin_sink->set_volume() should be called somewhere, that's not
+ * the case, because sinks that use volume sharing shouldn't have any
+ * internal volume that set_volume() would update. If you wonder
+ * whether the thread_info variables should be synced, yes, they
+ * should, and it's done by the PA_SINK_MESSAGE_FINISH_MOVE message
+ * handler. */
+ if (!pa_cvolume_equal(&i->origin_sink->reference_volume, &old_volume))
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, i->origin_sink->index);
+
+ /* Recursively update origin sink inputs. */
+ PA_IDXSET_FOREACH(origin_sink_input, i->origin_sink->inputs, idx)
+ update_volume_due_to_moving(origin_sink_input, dest);
+
+ } else {
+ old_volume = i->volume;
+
+ if (pa_sink_flat_volume_enabled(i->sink)) {
+ /* Ok, so this is a regular stream, and flat volume is enabled. The
+ * volume will have to be updated as follows:
+ *
+ * i->volume := i->reference_ratio * i->sink->reference_volume
+ * i->reference_ratio stays unchanged
+ * i->real_ratio := i->volume / i->sink->real_volume
+ * (handled later by pa_sink_set_volume)
+ * i->soft_volume := i->real_ratio * i->volume_factor
+ * (handled later by pa_sink_set_volume) */
+
+ i->volume = i->sink->reference_volume;
+ pa_cvolume_remap(&i->volume, &i->sink->channel_map, &i->channel_map);
+ pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
+
+ } else {
+ /* Ok, so this is a regular stream, and flat volume is disabled.
+ * The volume will have to be updated as follows:
+ *
+ * i->volume := i->reference_ratio
+ * i->reference_ratio stays unchanged
+ * i->real_ratio := i->reference_ratio
+ * i->soft_volume := i->real_ratio * i->volume_factor */
+
+ i->volume = i->reference_ratio;
+ i->real_ratio = i->reference_ratio;
+ pa_sw_cvolume_multiply(&i->soft_volume, &i->real_ratio, &i->volume_factor);
+ }
+
+ /* Notify others about the changed sink input volume. */
+ if (!pa_cvolume_equal(&i->volume, &old_volume)) {
+ /* XXX: In case i->sink has flat volume enabled, then real_ratio
+ * and soft_volume are not updated yet. Let's hope that the
+ * callback implementation doesn't care about those variables... */
+ if (i->volume_changed)
+ i->volume_changed(i);
+
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
+ }
+
+ /* If i->sink == dest, then recursion has finished, and we can finally call
+ * pa_sink_set_volume(), which will do the rest of the updates. */
+ if ((i->sink == dest) && pa_sink_flat_volume_enabled(i->sink))
+ pa_sink_set_volume(i->sink, NULL, FALSE, i->save_volume);
+}
+
/* Called from main context */
int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
pa_resampler *new_resampler;
@@ -1334,17 +1551,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
}
pa_sink_update_status(dest);
- if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
- pa_cvolume remapped;
-
- /* Make relative volumes absolute */
- remapped = dest->reference_volume;
- pa_cvolume_remap(&remapped, &dest->channel_map, &i->channel_map);
- pa_sw_cvolume_multiply(&i->volume, &i->reference_ratio, &remapped);
-
- /* We might need to update the sink's volume if we are in flat volume mode. */
- pa_sink_set_volume(i->sink, NULL, FALSE, i->save_volume);
- }
+ update_volume_due_to_moving(i, dest);
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0);
@@ -1353,9 +1560,6 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
/* Notify everyone */
pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], i);
- if (i->volume_changed)
- i->volume_changed(i);
-
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
return 0;
@@ -1464,23 +1668,15 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
switch (code) {
case PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME:
- if (pa_atomic_load(&i->before_ramping_v))
- i->thread_info.future_soft_volume = i->soft_volume;
-
if (!pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume)) {
- if (!pa_atomic_load(&i->before_ramping_v))
- 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_SOFT_MUTE:
- if (pa_atomic_load(&i->before_ramping_m))
- i->thread_info.future_muted = i->muted;
-
if (i->thread_info.muted != i->muted) {
- if (!pa_atomic_load(&i->before_ramping_m))
- i->thread_info.muted = i->muted;
+ i->thread_info.muted = i->muted;
pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
}
return 0;
@@ -1528,26 +1724,6 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
*r = i->thread_info.requested_sink_latency;
return 0;
}
-
- case PA_SINK_INPUT_MESSAGE_SET_ENVELOPE: {
- if (!i->thread_info.ramp_info.envelope)
- i->thread_info.ramp_info.envelope = pa_envelope_new(&i->sink->sample_spec);
-
- if (i->thread_info.ramp_info.envelope && i->thread_info.ramp_info.item) {
- pa_envelope_remove(i->thread_info.ramp_info.envelope, i->thread_info.ramp_info.item);
- i->thread_info.ramp_info.item = NULL;
- }
-
- i->thread_info.ramp_info.item = pa_envelope_add(i->thread_info.ramp_info.envelope, &i->using_def);
- i->thread_info.ramp_info.is_ramping = TRUE;
- i->thread_info.ramp_info.envelope_dead = FALSE;
- i->thread_info.ramp_info.envelope_dying = 0;
-
- if (i->thread_info.ramp_info.envelope)
- pa_envelope_restart(i->thread_info.ramp_info.envelope);
-
- return 0;
- }
}
return -PA_ERR_NOTIMPLEMENTED;
@@ -1710,237 +1886,3 @@ finish:
if (pl)
pa_proplist_free(pl);
}
-
-/* Called from IO context */
-static void sink_input_volume_ramping(pa_sink_input* i, pa_memchunk* chunk) {
- pa_assert(i);
- pa_assert(chunk);
- pa_assert(chunk->memblock);
- pa_assert(i->thread_info.ramp_info.is_ramping);
-
- /* Volume is adjusted with ramping effect here */
- pa_envelope_apply(i->thread_info.ramp_info.envelope, chunk);
-
- if (pa_envelope_is_finished(i->thread_info.ramp_info.envelope)) {
- i->thread_info.ramp_info.is_ramping = FALSE;
- if (pa_atomic_load(&i->before_ramping_v)) {
- i->thread_info.soft_volume = i->thread_info.future_soft_volume;
- pa_atomic_store(&i->before_ramping_v, 0);
- }
- else if (pa_atomic_load(&i->before_ramping_m)) {
- i->thread_info.muted = i->thread_info.future_muted;
- pa_atomic_store(&i->before_ramping_m, 0);
- }
- }
-}
-
-/*
- * Called from main context
- * This function should be called inside pa_sink_input_set_volume_with_ramping
- * should be called after soft_volume of sink_input and sink are all adjusted
- */
-static void sink_input_set_ramping_info(pa_sink_input* i, pa_volume_t pre_virtual_volume, pa_volume_t target_virtual_volume, pa_usec_t t) {
-
- int32_t target_abs_vol, target_apply_vol, pre_apply_vol;
- pa_assert(i);
-
- pa_log_debug("Sink input's soft volume is %d= %f ", pa_cvolume_avg(&i->soft_volume), pa_sw_volume_to_linear(pa_cvolume_avg(&i->soft_volume)));
-
- /* Calculation formula are target_abs_vol := i->soft_volume
- * target_apply_vol := lrint(pa_sw_volume_to_linear(target_abs_vol) * 0x10000)
- * pre_apply_vol := ( previous_virtual_volume / target_virtual_volume ) * target_apply_vol
- *
- * Will do volume adjustment inside pa_sink_input_peek
- */
- target_abs_vol = pa_cvolume_avg(&i->soft_volume);
- target_apply_vol = (int32_t) lrint(pa_sw_volume_to_linear(target_abs_vol) * 0x10000);
- pre_apply_vol = (int32_t) ((pa_sw_volume_to_linear(pre_virtual_volume) / pa_sw_volume_to_linear(target_virtual_volume)) * target_apply_vol);
-
- i->using_def.n_points = 2;
- i->using_def.points_x[0] = 0;
- i->using_def.points_x[1] = t;
- i->using_def.points_y.i[0] = pre_apply_vol;
- i->using_def.points_y.i[1] = target_apply_vol;
- i->using_def.points_y.f[0] = ((float) i->using_def.points_y.i[0]) /0x10000;
- i->using_def.points_y.f[1] = ((float) i->using_def.points_y.i[1]) /0x10000;
-
- pa_log_debug("Volume Ramping: Point 1 is %d=%f, Point 2 is %d=%f\n", i->using_def.points_y.i[0], i->using_def.points_y.f[0],
- i->using_def.points_y.i[1], i->using_def.points_y.f[1]);
-
- pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_ENVELOPE, NULL, 0, NULL) == 0);
-}
-
-/* Called from main context */
-static void sink_input_set_ramping_info_for_mute(pa_sink_input* i, pa_bool_t mute, pa_usec_t t) {
-
- int32_t cur_vol;
- pa_assert(i);
-
- i->using_def.n_points = 2;
- i->using_def.points_x[0] = 0;
- i->using_def.points_x[1] = t;
- cur_vol = (int32_t) lrint( pa_sw_volume_to_linear(pa_cvolume_avg(&i->soft_volume)) * 0x10000);
-
- if (mute) {
- i->using_def.points_y.i[0] = cur_vol;
- i->using_def.points_y.i[1] = 0;
- } else {
- i->using_def.points_y.i[0] = 0;
- i->using_def.points_y.i[1] = cur_vol;
- }
-
- i->using_def.points_y.f[0] = ((float) i->using_def.points_y.i[0]) /0x10000;
- i->using_def.points_y.f[1] = ((float) i->using_def.points_y.i[1]) /0x10000;
-
- pa_log_debug("Mute Ramping: Point 1 is %d=%f, Point 2 is %d=%f\n", i->using_def.points_y.i[0], i->using_def.points_y.f[0],
- i->using_def.points_y.i[1], i->using_def.points_y.f[1]);
-
- pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_ENVELOPE, NULL, 0, NULL) == 0);
-}
-
-/* Called from IO context */
-static void sink_input_release_envelope(pa_sink_input *i) {
- pa_assert(i);
- pa_assert(!i->thread_info.ramp_info.is_ramping);
- pa_assert(i->thread_info.ramp_info.envelope_dead);
-
- pa_envelope_free(i->thread_info.ramp_info.envelope);
- i->thread_info.ramp_info.envelope = NULL;
- i->thread_info.ramp_info.item = NULL;
-}
-
-/* Called from IO context */
-static void sink_input_rewind_ramp_info(pa_sink_input *i, size_t nbytes) {
- pa_assert(i);
-
- if (!i->thread_info.ramp_info.envelope_dead) {
- int32_t envelope_length;
-
- pa_assert(i->thread_info.ramp_info.envelope);
-
- envelope_length = pa_envelope_length(i->thread_info.ramp_info.envelope);
-
- if (i->thread_info.ramp_info.envelope_dying > envelope_length) {
- if ((int32_t) (i->thread_info.ramp_info.envelope_dying - nbytes) < envelope_length) {
- pa_log_debug("Envelope Become Alive");
- pa_envelope_rewind(i->thread_info.ramp_info.envelope, envelope_length - (i->thread_info.ramp_info.envelope_dying - nbytes));
- i->thread_info.ramp_info.is_ramping = TRUE;
- }
- } else if (i->thread_info.ramp_info.envelope_dying < envelope_length) {
- if ((i->thread_info.ramp_info.envelope_dying - (ssize_t) nbytes) <= 0) {
- pa_log_debug("Envelope Restart");
- pa_envelope_restart(i->thread_info.ramp_info.envelope);
- }
- else {
- pa_log_debug("Envelope Simple Rewind");
- pa_envelope_rewind(i->thread_info.ramp_info.envelope, nbytes);
- }
- }
-
- i->thread_info.ramp_info.envelope_dying -= nbytes;
- if (i->thread_info.ramp_info.envelope_dying <= 0)
- i->thread_info.ramp_info.envelope_dying = 0;
- }
-}
-
-void pa_sink_input_set_volume_with_ramping(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute, pa_usec_t t){
- pa_cvolume v;
- pa_volume_t previous_virtual_volume, target_virtual_volume;
-
- pa_sink_input_assert_ref(i);
- pa_assert_ctl_context();
- pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
- pa_assert(volume);
- pa_assert(pa_cvolume_valid(volume));
- pa_assert(volume->channels == 1 || pa_cvolume_compatible(volume, &i->sample_spec));
-
- if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
- v = i->sink->reference_volume;
- pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map);
-
- if (pa_cvolume_compatible(volume, &i->sample_spec))
- volume = pa_sw_cvolume_multiply(&v, &v, volume);
- else
- volume = pa_sw_cvolume_multiply_scalar(&v, &v, pa_cvolume_max(volume));
- } else {
-
- if (!pa_cvolume_compatible(volume, &i->sample_spec)) {
- v = i->volume;
- volume = pa_cvolume_scale(&v, pa_cvolume_max(volume));
- }
- }
-
- if (pa_cvolume_equal(volume, &i->volume)) {
- i->save_volume = i->save_volume || save;
- return;
- }
-
- previous_virtual_volume = pa_cvolume_avg(&i->volume);
- target_virtual_volume = pa_cvolume_avg(volume);
-
- if (t > 0 && target_virtual_volume > 0)
- pa_log_debug("SetVolumeWithRamping: Virtual Volume From %u=%f to %u=%f\n", previous_virtual_volume, pa_sw_volume_to_linear(previous_virtual_volume),
- target_virtual_volume, pa_sw_volume_to_linear(target_virtual_volume));
-
- i->volume = *volume;
- i->save_volume = save;
-
- /* Set this flag before the following code modify i->thread_info.soft_volume */
- if (t > 0 && target_virtual_volume > 0)
- pa_atomic_store(&i->before_ramping_v, 1);
-
- if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
- /* We are in flat volume mode, so let's update all sink input
- * volumes and update the flat volume of the sink */
-
- pa_sink_set_volume(i->sink, NULL, TRUE, save);
-
- } else {
- /* OK, we are in normal volume mode. The volume only affects
- * ourselves */
- set_real_ratio(i, volume);
-
- /* Copy the new soft_volume to the thread_info struct */
- pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
- }
-
- if (t > 0 && target_virtual_volume > 0)
- sink_input_set_ramping_info(i, previous_virtual_volume, target_virtual_volume, t);
-
- /* The volume changed, let's tell people so */
- if (i->volume_changed)
- i->volume_changed(i);
-
- /* The virtual volume changed, let's tell people so */
- pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
-}
-
-void pa_sink_input_set_mute_with_ramping(pa_sink_input *i, pa_bool_t mute, pa_bool_t save, pa_usec_t t){
-
- pa_sink_input_assert_ref(i);
- pa_assert_ctl_context();
- pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
-
- if (!i->muted == !mute) {
- i->save_muted = i->save_muted || mute;
- return;
- }
-
- i->muted = mute;
- i->save_muted = save;
-
- /* Set this flag before the following code modify i->thread_info.muted, otherwise distortion will be heard */
- if (t > 0)
- pa_atomic_store(&i->before_ramping_m, 1);
-
- pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE, NULL, 0, NULL) == 0);
-
- if (t > 0)
- sink_input_set_ramping_info_for_mute(i, mute, t);
-
- /* The mute status changed, let's tell people so */
- if (i->mute_changed)
- i->mute_changed(i);
-
- pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
-}
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index f81e2d4b..588005fd 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -35,7 +35,6 @@ typedef struct pa_sink_input pa_sink_input;
#include <pulsecore/client.h>
#include <pulsecore/sink.h>
#include <pulsecore/core.h>
-#include <pulsecore/envelope.h>
typedef enum pa_sink_input_state {
PA_SINK_INPUT_INIT, /*< The stream is not active yet, because pa_sink_input_put() has not been called yet */
@@ -83,7 +82,8 @@ struct pa_sink_input {
pa_module *module; /* may be NULL */
pa_client *client; /* may be NULL */
- pa_sink *sink; /* NULL while we are being moved */
+ pa_sink *sink; /* NULL while we are being moved */
+ pa_sink *origin_sink; /* only set by filter sinks */
/* A sink input may be connected to multiple source outputs
* directly, so that they don't get mixed data of the entire
@@ -234,23 +234,8 @@ struct pa_sink_input {
pa_usec_t requested_sink_latency;
pa_hashmap *direct_outputs;
-
- struct {
- pa_bool_t is_ramping:1;
- pa_bool_t envelope_dead:1;
- int32_t envelope_dying; /* Increasing while envelop is not dead. Reduce it while process_rewind. */
- pa_envelope *envelope;
- pa_envelope_item *item;
- } ramp_info;
- pa_cvolume future_soft_volume;
- pa_bool_t future_muted;
-
} thread_info;
- pa_atomic_t before_ramping_v; /* Indicates future volume */
- pa_atomic_t before_ramping_m; /* Indicates future mute */
- pa_envelope_def using_def;
-
void *userdata;
};
@@ -265,7 +250,6 @@ enum {
PA_SINK_INPUT_MESSAGE_SET_STATE,
PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY,
PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY,
- PA_SINK_INPUT_MESSAGE_SET_ENVELOPE,
PA_SINK_INPUT_MESSAGE_MAX
};
@@ -285,6 +269,7 @@ typedef struct pa_sink_input_new_data {
pa_client *client;
pa_sink *sink;
+ pa_sink *origin_sink;
pa_resample_method_t resample_method;
@@ -310,6 +295,7 @@ typedef struct pa_sink_input_new_data {
pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data);
void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec);
void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map);
+pa_bool_t pa_sink_input_new_data_is_volume_writable(pa_sink_input_new_data *data);
void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume);
void pa_sink_input_new_data_apply_volume_factor(pa_sink_input_new_data *data, const pa_cvolume *volume_factor);
void pa_sink_input_new_data_apply_volume_factor_sink(pa_sink_input_new_data *data, const pa_cvolume *volume_factor);
@@ -354,6 +340,8 @@ void pa_sink_input_kill(pa_sink_input*i);
pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency);
+pa_bool_t pa_sink_input_is_volume_readable(pa_sink_input *i);
+pa_bool_t pa_sink_input_is_volume_writable(pa_sink_input *i);
void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute);
pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute);
@@ -402,8 +390,4 @@ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret);
#define pa_sink_input_assert_io_context(s) \
pa_assert(pa_thread_mq_get() || !PA_SINK_INPUT_IS_LINKED((s)->state))
-/* Volume ramping*/
-void pa_sink_input_set_volume_with_ramping(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute, pa_usec_t t);
-void pa_sink_input_set_mute_with_ramping(pa_sink_input *i, pa_bool_t mute, pa_bool_t save, pa_usec_t t);
-
#endif
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 62000e0d..839b7d44 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -226,8 +226,14 @@ pa_sink* pa_sink_new(
pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
- if (!data->volume_is_set)
+ /* FIXME: There should probably be a general function for checking whether
+ * the sink volume is allowed to be set, like there is for sink inputs. */
+ pa_assert(!data->volume_is_set || !(flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
+
+ if (!data->volume_is_set) {
pa_cvolume_reset(&data->volume, data->sample_spec.channels);
+ data->save_volume = FALSE;
+ }
pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));
@@ -269,6 +275,7 @@ pa_sink* pa_sink_new(
s->inputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
+ s->input_to_master = NULL;
s->reference_volume = s->real_volume = data->volume;
pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
@@ -446,6 +453,7 @@ void pa_sink_put(pa_sink* s) {
pa_assert_ctl_context();
pa_assert(s->state == PA_SINK_INIT);
+ pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) || s->input_to_master);
/* The following fields must be initialized properly when calling _put() */
pa_assert(s->asyncmsgq);
@@ -455,22 +463,43 @@ void pa_sink_put(pa_sink* s) {
* special exception we allow volume related flags to be set
* between _new() and _put(). */
- if (!(s->flags & PA_SINK_HW_VOLUME_CTRL))
+ /* XXX: Currently decibel volume is disabled for all sinks that use volume
+ * sharing. When the master sink supports decibel volume, it would be good
+ * to have the flag also in the filter sink, but currently we don't do that
+ * so that the flags of the filter sink never change when it's moved from
+ * a master sink to another. One solution for this problem would be to
+ * remove user-visible volume altogether from filter sinks when volume
+ * sharing is used, but the current approach was easier to implement... */
+ if (!(s->flags & PA_SINK_HW_VOLUME_CTRL) && !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
s->flags |= PA_SINK_DECIBEL_VOLUME;
if ((s->flags & PA_SINK_DECIBEL_VOLUME) && s->core->flat_volumes)
s->flags |= PA_SINK_FLAT_VOLUME;
- /* We assume that if the sink implementor changed the default
- * volume he did so in real_volume, because that is the usual
- * place where he is supposed to place his changes. */
- s->reference_volume = s->real_volume;
+ if (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) {
+ pa_sink *root_sink = s->input_to_master->sink;
+
+ while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+ root_sink = root_sink->input_to_master->sink;
+
+ s->reference_volume = root_sink->reference_volume;
+ pa_cvolume_remap(&s->reference_volume, &root_sink->channel_map, &s->channel_map);
+
+ s->real_volume = root_sink->real_volume;
+ pa_cvolume_remap(&s->real_volume, &root_sink->channel_map, &s->channel_map);
+ } else
+ /* We assume that if the sink implementor changed the default
+ * volume he did so in real_volume, because that is the usual
+ * place where he is supposed to place his changes. */
+ s->reference_volume = s->real_volume;
s->thread_info.soft_volume = s->soft_volume;
s->thread_info.soft_muted = s->muted;
pa_sw_cvolume_multiply(&s->thread_info.current_hw_volume, &s->soft_volume, &s->real_volume);
- pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SINK_DECIBEL_VOLUME));
+ pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL)
+ || (s->base_volume == PA_VOLUME_NORM
+ && ((s->flags & PA_SINK_DECIBEL_VOLUME || (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)))));
pa_assert(!(s->flags & PA_SINK_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == (s->thread_info.fixed_latency != 0));
pa_assert(!(s->flags & PA_SINK_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_LATENCY));
@@ -1195,47 +1224,61 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
return usec;
}
-static pa_cvolume* cvolume_remap_minimal_impact(
- pa_cvolume *v,
- const pa_cvolume *template,
- const pa_channel_map *from,
- const pa_channel_map *to) {
+/* Called from the main thread (and also from the IO thread while the main
+ * thread is waiting).
+ *
+ * When a sink uses volume sharing, it never has the PA_SINK_FLAT_VOLUME flag
+ * set. Instead, flat volume mode is detected by checking whether the root sink
+ * has the flag set. */
+pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s) {
+ pa_sink_assert_ref(s);
- pa_cvolume t;
+ while (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+ s = s->input_to_master->sink;
- pa_assert(v);
- pa_assert(template);
- pa_assert(from);
- pa_assert(to);
+ return (s->flags & PA_SINK_FLAT_VOLUME);
+}
- pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL);
- pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(template, to), NULL);
+/* Called from main context. */
+static void compute_reference_ratio(pa_sink_input *i) {
+ unsigned c = 0;
+ pa_cvolume remapped;
- /* Much like pa_cvolume_remap(), but tries to minimize impact when
- * mapping from sink input to sink volumes:
- *
- * If template is a possible remapping from v it is used instead
- * of remapping anew.
+ pa_assert(i);
+ pa_assert(pa_sink_flat_volume_enabled(i->sink));
+
+ /*
+ * Calculates the reference ratio from the sink's reference
+ * volume. This basically calculates:
*
- * If the channel maps don't match we set an all-channel volume on
- * the sink to ensure that changing a volume on one stream has no
- * effect that cannot be compensated for in another stream that
- * does not have the same channel map as the sink. */
+ * i->reference_ratio = i->volume / i->sink->reference_volume
+ */
- if (pa_channel_map_equal(from, to))
- return v;
+ remapped = i->sink->reference_volume;
+ pa_cvolume_remap(&remapped, &i->sink->channel_map, &i->channel_map);
- t = *template;
- if (pa_cvolume_equal(pa_cvolume_remap(&t, to, from), v)) {
- *v = *template;
- return v;
- }
+ i->reference_ratio.channels = i->sample_spec.channels;
- pa_cvolume_set(v, to->channels, pa_cvolume_max(v));
- return v;
+ for (c = 0; c < i->sample_spec.channels; c++) {
+
+ /* We don't update when the sink volume is 0 anyway */
+ if (remapped.values[c] <= PA_VOLUME_MUTED)
+ continue;
+
+ /* Don't update the reference ratio unless necessary */
+ if (pa_sw_volume_multiply(
+ i->reference_ratio.values[c],
+ remapped.values[c]) == i->volume.values[c])
+ continue;
+
+ i->reference_ratio.values[c] = pa_sw_volume_divide(
+ i->volume.values[c],
+ remapped.values[c]);
+ }
}
-/* Called from main context */
+/* Called from main context. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
static void compute_reference_ratios(pa_sink *s) {
uint32_t idx;
pa_sink_input *i;
@@ -1243,44 +1286,18 @@ static void compute_reference_ratios(pa_sink *s) {
pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
- pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+ pa_assert(pa_sink_flat_volume_enabled(s));
PA_IDXSET_FOREACH(i, s->inputs, idx) {
- unsigned c;
- pa_cvolume remapped;
-
- /*
- * Calculates the reference volume from the sink's reference
- * volume. This basically calculates:
- *
- * i->reference_ratio = i->volume / s->reference_volume
- */
-
- remapped = s->reference_volume;
- pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
-
- i->reference_ratio.channels = i->sample_spec.channels;
-
- for (c = 0; c < i->sample_spec.channels; c++) {
-
- /* We don't update when the sink volume is 0 anyway */
- if (remapped.values[c] <= PA_VOLUME_MUTED)
- continue;
-
- /* Don't update the reference ratio unless necessary */
- if (pa_sw_volume_multiply(
- i->reference_ratio.values[c],
- remapped.values[c]) == i->volume.values[c])
- continue;
+ compute_reference_ratio(i);
- i->reference_ratio.values[c] = pa_sw_volume_divide(
- i->volume.values[c],
- remapped.values[c]);
- }
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ compute_reference_ratios(i->origin_sink);
}
}
-/* Called from main context */
+/* Called from main context. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
static void compute_real_ratios(pa_sink *s) {
pa_sink_input *i;
uint32_t idx;
@@ -1288,12 +1305,24 @@ static void compute_real_ratios(pa_sink *s) {
pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
- pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+ pa_assert(pa_sink_flat_volume_enabled(s));
PA_IDXSET_FOREACH(i, s->inputs, idx) {
unsigned c;
pa_cvolume remapped;
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ /* The origin sink uses volume sharing, so this input's real ratio
+ * is handled as a special case - the real ratio must be 0 dB, and
+ * as a result i->soft_volume must equal i->volume_factor. */
+ pa_cvolume_reset(&i->real_ratio, i->real_ratio.channels);
+ i->soft_volume = i->volume_factor;
+
+ compute_real_ratios(i->origin_sink);
+
+ continue;
+ }
+
/*
* This basically calculates:
*
@@ -1334,23 +1363,144 @@ static void compute_real_ratios(pa_sink *s) {
}
}
-/* Called from main thread */
-static void compute_real_volume(pa_sink *s) {
+static pa_cvolume *cvolume_remap_minimal_impact(
+ pa_cvolume *v,
+ const pa_cvolume *template,
+ const pa_channel_map *from,
+ const pa_channel_map *to) {
+
+ pa_cvolume t;
+
+ pa_assert(v);
+ pa_assert(template);
+ pa_assert(from);
+ pa_assert(to);
+ pa_assert(pa_cvolume_compatible_with_channel_map(v, from));
+ pa_assert(pa_cvolume_compatible_with_channel_map(template, to));
+
+ /* Much like pa_cvolume_remap(), but tries to minimize impact when
+ * mapping from sink input to sink volumes:
+ *
+ * If template is a possible remapping from v it is used instead
+ * of remapping anew.
+ *
+ * If the channel maps don't match we set an all-channel volume on
+ * the sink to ensure that changing a volume on one stream has no
+ * effect that cannot be compensated for in another stream that
+ * does not have the same channel map as the sink. */
+
+ if (pa_channel_map_equal(from, to))
+ return v;
+
+ t = *template;
+ if (pa_cvolume_equal(pa_cvolume_remap(&t, to, from), v)) {
+ *v = *template;
+ return v;
+ }
+
+ pa_cvolume_set(v, to->channels, pa_cvolume_max(v));
+ return v;
+}
+
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static void get_maximum_input_volume(pa_sink *s, pa_cvolume *max_volume, const pa_channel_map *channel_map) {
+ pa_sink_input *i;
+ uint32_t idx;
+
+ pa_sink_assert_ref(s);
+ pa_assert(max_volume);
+ pa_assert(channel_map);
+ pa_assert(pa_sink_flat_volume_enabled(s));
+
+ PA_IDXSET_FOREACH(i, s->inputs, idx) {
+ pa_cvolume remapped;
+
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ get_maximum_input_volume(i->origin_sink, max_volume, channel_map);
+
+ /* Ignore this input. The origin sink uses volume sharing, so this
+ * input's volume will be set to be equal to the root sink's real
+ * volume. Obviously this input's current volume must not then
+ * affect what the root sink's real volume will be. */
+ continue;
+ }
+
+ remapped = i->volume;
+ cvolume_remap_minimal_impact(&remapped, max_volume, &i->channel_map, channel_map);
+ pa_cvolume_merge(max_volume, max_volume, &remapped);
+ }
+}
+
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static pa_bool_t has_inputs(pa_sink *s) {
pa_sink_input *i;
uint32_t idx;
pa_sink_assert_ref(s);
+
+ PA_IDXSET_FOREACH(i, s->inputs, idx) {
+ if (!i->origin_sink || !(i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) || has_inputs(i->origin_sink))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static void update_real_volume(pa_sink *s, const pa_cvolume *new_volume, pa_channel_map *channel_map) {
+ pa_sink_input *i;
+ uint32_t idx;
+
+ pa_sink_assert_ref(s);
+ pa_assert(new_volume);
+ pa_assert(channel_map);
+
+ s->real_volume = *new_volume;
+ pa_cvolume_remap(&s->real_volume, channel_map, &s->channel_map);
+
+ PA_IDXSET_FOREACH(i, s->inputs, idx) {
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ if (pa_sink_flat_volume_enabled(s)) {
+ pa_cvolume old_volume = i->volume;
+
+ /* Follow the root sink's real volume. */
+ i->volume = *new_volume;
+ pa_cvolume_remap(&i->volume, channel_map, &i->channel_map);
+ compute_reference_ratio(i);
+
+ /* The volume changed, let's tell people so */
+ if (!pa_cvolume_equal(&old_volume, &i->volume)) {
+ if (i->volume_changed)
+ i->volume_changed(i);
+
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
+ }
+
+ update_real_volume(i->origin_sink, new_volume, channel_map);
+ }
+ }
+}
+
+/* Called from main thread. Only called for the root sink in shared volume
+ * cases. */
+static void compute_real_volume(pa_sink *s) {
+ pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
- pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+ pa_assert(pa_sink_flat_volume_enabled(s));
+ pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
/* This determines the maximum volume of all streams and sets
* s->real_volume accordingly. */
- if (pa_idxset_isempty(s->inputs)) {
- /* In the special case that we have no sink input we leave the
+ if (!has_inputs(s)) {
+ /* In the special case that we have no sink inputs we leave the
* volume unmodified. */
- s->real_volume = s->reference_volume;
+ update_real_volume(s, &s->reference_volume, &s->channel_map);
return;
}
@@ -1358,20 +1508,16 @@ static void compute_real_volume(pa_sink *s) {
/* First let's determine the new maximum volume of all inputs
* connected to this sink */
- PA_IDXSET_FOREACH(i, s->inputs, idx) {
- pa_cvolume remapped;
-
- remapped = i->volume;
- cvolume_remap_minimal_impact(&remapped, &s->real_volume, &i->channel_map, &s->channel_map);
- pa_cvolume_merge(&s->real_volume, &s->real_volume, &remapped);
- }
+ get_maximum_input_volume(s, &s->real_volume, &s->channel_map);
+ update_real_volume(s, &s->real_volume, &s->channel_map);
/* Then, let's update the real ratios/soft volumes of all inputs
* connected to this sink */
compute_real_ratios(s);
}
-/* Called from main thread */
+/* Called from main thread. Only called for the root sink in shared volume
+ * cases, except for internal recursive calls. */
static void propagate_reference_volume(pa_sink *s) {
pa_sink_input *i;
uint32_t idx;
@@ -1379,14 +1525,23 @@ static void propagate_reference_volume(pa_sink *s) {
pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
- pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+ pa_assert(pa_sink_flat_volume_enabled(s));
/* 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 */
PA_IDXSET_FOREACH(i, s->inputs, idx) {
- pa_cvolume old_volume, remapped;
+ pa_cvolume old_volume;
+
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ propagate_reference_volume(i->origin_sink);
+
+ /* Since the origin sink uses volume sharing, this input's volume
+ * needs to be updated to match the root sink's real volume, but
+ * that will be done later in update_shared_real_volume(). */
+ continue;
+ }
old_volume = i->volume;
@@ -1394,9 +1549,9 @@ static void propagate_reference_volume(pa_sink *s) {
*
* i->volume := s->reference_volume * i->reference_ratio */
- remapped = s->reference_volume;
- pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
- pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio);
+ i->volume = s->reference_volume;
+ pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map);
+ pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
/* The volume changed, let's tell people so */
if (!pa_cvolume_equal(&old_volume, &i->volume)) {
@@ -1409,6 +1564,54 @@ static void propagate_reference_volume(pa_sink *s) {
}
}
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. The return value indicates
+ * whether any reference volume actually changed. */
+static pa_bool_t update_reference_volume(pa_sink *s, const pa_cvolume *v, const pa_channel_map *channel_map, pa_bool_t save) {
+ pa_cvolume volume;
+ pa_bool_t reference_volume_changed;
+ pa_sink_input *i;
+ uint32_t idx;
+
+ pa_sink_assert_ref(s);
+ pa_assert(PA_SINK_IS_LINKED(s->state));
+ pa_assert(v);
+ pa_assert(channel_map);
+ pa_assert(pa_cvolume_valid(v));
+
+ volume = *v;
+ pa_cvolume_remap(&volume, channel_map, &s->channel_map);
+
+ reference_volume_changed = !pa_cvolume_equal(&volume, &s->reference_volume);
+ s->reference_volume = volume;
+
+ s->save_volume = (!reference_volume_changed && s->save_volume) || save;
+
+ if (reference_volume_changed)
+ pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ else if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ /* If the root sink's volume doesn't change, then there can't be any
+ * changes in the other sinks in the sink tree either.
+ *
+ * It's probably theoretically possible that even if the root sink's
+ * volume changes slightly, some filter sink doesn't change its volume
+ * due to rounding errors. If that happens, we still want to propagate
+ * the changed root sink volume to the sinks connected to the
+ * intermediate sink that didn't change its volume. This theoretical
+ * possiblity is the reason why we have that !(s->flags &
+ * PA_SINK_SHARE_VOLUME_WITH_MASTER) condition. Probably nobody would
+ * notice even if we returned here FALSE always if
+ * reference_volume_changed is FALSE. */
+ return FALSE;
+
+ PA_IDXSET_FOREACH(i, s->inputs, idx) {
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ update_reference_volume(i->origin_sink, v, channel_map, FALSE);
+ }
+
+ return TRUE;
+}
+
/* Called from main thread */
void pa_sink_set_volume(
pa_sink *s,
@@ -1416,14 +1619,14 @@ void pa_sink_set_volume(
pa_bool_t send_msg,
pa_bool_t save) {
- pa_cvolume old_reference_volume;
- pa_bool_t reference_changed;
+ pa_cvolume new_reference_volume;
+ pa_sink *root_sink = s;
pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
pa_assert(!volume || pa_cvolume_valid(volume));
- pa_assert(volume || (s->flags & PA_SINK_FLAT_VOLUME));
+ pa_assert(volume || pa_sink_flat_volume_enabled(s));
pa_assert(!volume || volume->channels == 1 || pa_cvolume_compatible(volume, &s->sample_spec));
/* make sure we don't change the volume when a PASSTHROUGH input is connected */
@@ -1444,76 +1647,80 @@ void pa_sink_set_volume(
}
}
+ /* In case of volume sharing, the volume is set for the root sink first,
+ * from which it's then propagated to the sharing sinks. */
+ while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+ root_sink = root_sink->input_to_master->sink;
+
/* As a special exception we accept mono volumes on all sinks --
* even on those with more complex channel maps */
+ if (volume) {
+ if (pa_cvolume_compatible(volume, &s->sample_spec))
+ new_reference_volume = *volume;
+ else {
+ new_reference_volume = s->reference_volume;
+ pa_cvolume_scale(&new_reference_volume, pa_cvolume_max(volume));
+ }
+
+ pa_cvolume_remap(&new_reference_volume, &s->channel_map, &root_sink->channel_map);
+ }
+
/* If volume is NULL we synchronize the sink's real and reference
* volumes with the stream volumes. If it is not NULL we update
* the reference_volume with it. */
- old_reference_volume = s->reference_volume;
-
if (volume) {
-
- if (pa_cvolume_compatible(volume, &s->sample_spec))
- s->reference_volume = *volume;
- else
- pa_cvolume_scale(&s->reference_volume, pa_cvolume_max(volume));
-
- if (s->flags & PA_SINK_FLAT_VOLUME) {
- /* OK, propagate this volume change back to the inputs */
- propagate_reference_volume(s);
-
- /* And now recalculate the real volume */
- compute_real_volume(s);
- } else
- s->real_volume = s->reference_volume;
+ if (update_reference_volume(root_sink, &new_reference_volume, &root_sink->channel_map, save)) {
+ if (pa_sink_flat_volume_enabled(root_sink)) {
+ /* OK, propagate this volume change back to the inputs */
+ propagate_reference_volume(root_sink);
+
+ /* And now recalculate the real volume */
+ compute_real_volume(root_sink);
+ } else
+ update_real_volume(root_sink, &root_sink->reference_volume, &root_sink->channel_map);
+ }
} else {
- pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+ pa_assert(pa_sink_flat_volume_enabled(root_sink));
/* Ok, let's determine the new real volume */
- compute_real_volume(s);
+ compute_real_volume(root_sink);
/* Let's 'push' the reference volume if necessary */
- pa_cvolume_merge(&s->reference_volume, &s->reference_volume, &s->real_volume);
+ pa_cvolume_merge(&new_reference_volume, &s->reference_volume, &root_sink->real_volume);
+ update_reference_volume(root_sink, &new_reference_volume, &root_sink->channel_map, save);
- /* We need to fix the reference ratios of all streams now that
- * we changed the reference volume */
- compute_reference_ratios(s);
+ /* Now that the reference volume is updated, we can update the streams'
+ * reference ratios. */
+ compute_reference_ratios(root_sink);
}
- reference_changed = !pa_cvolume_equal(&old_reference_volume, &s->reference_volume);
- s->save_volume = (!reference_changed && s->save_volume) || save;
-
- if (s->set_volume) {
+ if (root_sink->set_volume) {
/* If we have a function set_volume(), then we do not apply a
* soft volume by default. However, set_volume() is free to
- * apply one to s->soft_volume */
+ * apply one to root_sink->soft_volume */
- pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
- if (!(s->flags & PA_SINK_SYNC_VOLUME))
- s->set_volume(s);
- else
- send_msg = TRUE;
+ pa_cvolume_reset(&root_sink->soft_volume, root_sink->sample_spec.channels);
+ if (!(root_sink->flags & PA_SINK_SYNC_VOLUME))
+ root_sink->set_volume(root_sink);
} else
/* If we have no function set_volume(), then the soft volume
- * becomes the virtual volume */
- s->soft_volume = s->real_volume;
+ * becomes the real volume */
+ root_sink->soft_volume = root_sink->real_volume;
- /* This tells the sink that soft and/or virtual volume changed */
+ /* This tells the sink that soft volume and/or real volume changed */
if (send_msg)
- pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL) == 0);
-
- if (reference_changed)
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ pa_assert_se(pa_asyncmsgq_send(root_sink->asyncmsgq, PA_MSGOBJECT(root_sink), PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL) == 0);
}
/* Called from the io thread if sync volume is used, otherwise from the main thread.
* Only to be called by sink implementor */
void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
pa_sink_assert_ref(s);
+ pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
if (s->flags & PA_SINK_SYNC_VOLUME)
pa_sink_assert_io_context(s);
else
@@ -1530,12 +1737,14 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
s->thread_info.soft_volume = s->soft_volume;
}
+/* Called from the main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume) {
pa_sink_input *i;
uint32_t idx;
- pa_cvolume old_reference_volume;
pa_sink_assert_ref(s);
+ pa_assert(old_real_volume);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
@@ -1544,20 +1753,18 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
* reference volume and then rebuild the stream volumes based on
* i->real_ratio which should stay fixed. */
- if (old_real_volume && pa_cvolume_equal(old_real_volume, &s->real_volume))
- return;
-
- old_reference_volume = s->reference_volume;
+ if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+ if (pa_cvolume_equal(old_real_volume, &s->real_volume))
+ return;
- /* 1. Make the real volume the reference volume */
- s->reference_volume = s->real_volume;
+ /* 1. Make the real volume the reference volume */
+ update_reference_volume(s, &s->real_volume, &s->channel_map, TRUE);
+ }
- if (s->flags & PA_SINK_FLAT_VOLUME) {
+ if (pa_sink_flat_volume_enabled(s)) {
PA_IDXSET_FOREACH(i, s->inputs, idx) {
- pa_cvolume old_volume, remapped;
-
- old_volume = i->volume;
+ pa_cvolume old_volume = i->volume;
/* 2. Since the sink's reference and real volumes are equal
* now our ratios should be too. */
@@ -1571,9 +1778,9 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
* i->volume = s->reference_volume * i->reference_ratio
*
* This is identical to propagate_reference_volume() */
- remapped = s->reference_volume;
- pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
- pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio);
+ i->volume = s->reference_volume;
+ pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map);
+ pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
/* Notify if something changed */
if (!pa_cvolume_equal(&old_volume, &i->volume)) {
@@ -1583,16 +1790,17 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
}
+
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ propagate_real_volume(i->origin_sink, old_real_volume);
}
}
/* Something got changed in the hardware. It probably makes sense
* to save changed hw settings given that hw volume changes not
* triggered by PA are almost certainly done by the user. */
- s->save_volume = TRUE;
-
- if (!pa_cvolume_equal(&old_reference_volume, &s->reference_volume))
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ s->save_volume = TRUE;
}
/* Called from io thread */
@@ -1612,6 +1820,8 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
if (s->refresh_volume || force_refresh) {
struct pa_cvolume old_real_volume;
+ pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
+
old_real_volume = s->real_volume;
if (!(s->flags & PA_SINK_SYNC_VOLUME) && s->get_volume)
@@ -1619,25 +1829,27 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
+ update_real_volume(s, &s->real_volume, &s->channel_map);
propagate_real_volume(s, &old_real_volume);
}
return &s->reference_volume;
}
-/* Called from main thread */
+/* Called from main thread. In volume sharing cases, only the root sink may
+ * call this. */
void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_real_volume) {
pa_cvolume old_real_volume;
pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_assert(PA_SINK_IS_LINKED(s->state));
+ pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
/* The sink implementor may call this if the volume changed to make sure everyone is notified */
old_real_volume = s->real_volume;
- s->real_volume = *new_real_volume;
-
+ update_real_volume(s, new_real_volume, &s->channel_map);
propagate_real_volume(s, &old_real_volume);
}
@@ -1844,18 +2056,30 @@ static void sync_input_volumes_within_thread(pa_sink *s) {
pa_sink_assert_io_context(s);
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
- if (pa_atomic_load(&i->before_ramping_v))
- i->thread_info.future_soft_volume = i->soft_volume;
-
if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
continue;
- if (!pa_atomic_load(&i->before_ramping_v))
- 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);
}
}
+/* Called from the IO thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static void set_shared_volume_within_thread(pa_sink *s) {
+ pa_sink_input *i = NULL;
+ void *state = NULL;
+
+ pa_sink_assert_ref(s);
+
+ PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+
+ PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
+ if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+ set_shared_volume_within_thread(i->origin_sink);
+ }
+}
+
/* 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);
@@ -1912,7 +2136,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
/* In flat volume mode we need to update the volume as
* well */
- return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
}
case PA_SINK_MESSAGE_REMOVE_INPUT: {
@@ -1955,7 +2179,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
/* In flat volume mode we need to update the volume as
* well */
- return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
}
case PA_SINK_MESSAGE_START_MOVE: {
@@ -2000,7 +2224,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
/* In flat volume mode we need to update the volume as
* well */
- return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
}
case PA_SINK_MESSAGE_FINISH_MOVE: {
@@ -2041,9 +2265,17 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
pa_sink_request_rewind(s, nbytes);
}
- /* In flat volume mode we need to update the volume as
- * well */
- return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+ return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
+ }
+
+ case PA_SINK_MESSAGE_SET_SHARED_VOLUME: {
+ pa_sink *root_sink = s;
+
+ while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+ root_sink = root_sink->input_to_master->sink;
+
+ set_shared_volume_within_thread(root_sink);
+ return 0;
}
case PA_SINK_MESSAGE_SET_VOLUME_SYNCED:
@@ -2061,9 +2293,6 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
pa_sink_request_rewind(s, (size_t) -1);
}
- if (!(s->flags & PA_SINK_FLAT_VOLUME))
- return 0;
-
/* Fall through ... */
case PA_SINK_MESSAGE_SYNC_VOLUMES:
@@ -2503,22 +2732,22 @@ void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_
/* Called from main thread */
void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
- pa_sink_assert_ref(s);
- pa_assert_ctl_context();
- pa_assert(min_latency);
- pa_assert(max_latency);
+ pa_sink_assert_ref(s);
+ pa_assert_ctl_context();
+ pa_assert(min_latency);
+ pa_assert(max_latency);
- if (PA_SINK_IS_LINKED(s->state)) {
- pa_usec_t r[2] = { 0, 0 };
+ if (PA_SINK_IS_LINKED(s->state)) {
+ pa_usec_t r[2] = { 0, 0 };
- pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
- *min_latency = r[0];
- *max_latency = r[1];
- } else {
- *min_latency = s->thread_info.min_latency;
- *max_latency = s->thread_info.max_latency;
- }
+ *min_latency = r[0];
+ *max_latency = r[1];
+ } else {
+ *min_latency = s->thread_info.min_latency;
+ *max_latency = s->thread_info.max_latency;
+ }
}
/* Called from IO thread */
@@ -2699,6 +2928,8 @@ int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) {
s->active_port = port;
s->save_port = save;
+ pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s);
+
return 0;
}
@@ -2942,11 +3173,11 @@ void pa_sink_volume_change_push(pa_sink *s) {
PA_LLIST_INSERT_AFTER(pa_sink_volume_change, s->thread_info.volume_changes, c, nc);
}
- pa_log_debug("Volume going %s to %d at %llu", direction, pa_cvolume_avg(&nc->hw_volume), nc->at);
+ pa_log_debug("Volume going %s to %d at %llu", direction, pa_cvolume_avg(&nc->hw_volume), (long long unsigned) nc->at);
/* We can ignore volume events that came earlier but should happen later than this. */
PA_LLIST_FOREACH(c, nc->next) {
- pa_log_debug("Volume change to %d at %llu was dropped", pa_cvolume_avg(&c->hw_volume), c->at);
+ pa_log_debug("Volume change to %d at %llu was dropped", pa_cvolume_avg(&c->hw_volume), (long long unsigned) c->at);
pa_sink_volume_change_free(c);
}
nc->next = NULL;
@@ -2977,7 +3208,8 @@ pa_bool_t pa_sink_volume_change_apply(pa_sink *s, pa_usec_t *usec_to_next) {
while (s->thread_info.volume_changes && now >= s->thread_info.volume_changes->at) {
pa_sink_volume_change *c = s->thread_info.volume_changes;
PA_LLIST_REMOVE(pa_sink_volume_change, s->thread_info.volume_changes, c);
- pa_log_debug("Volume change to %d at %llu was written %llu usec late", pa_cvolume_avg(&c->hw_volume), c->at, now - c->at);
+ pa_log_debug("Volume change to %d at %llu was written %llu usec late",
+ pa_cvolume_avg(&c->hw_volume), (long long unsigned) c->at, (long long unsigned) (now - c->at));
ret = TRUE;
s->thread_info.current_hw_volume = c->hw_volume;
pa_sink_volume_change_free(c);
@@ -2990,7 +3222,7 @@ pa_bool_t pa_sink_volume_change_apply(pa_sink *s, pa_usec_t *usec_to_next) {
if (usec_to_next)
*usec_to_next = s->thread_info.volume_changes->at - now;
if (pa_log_ratelimit(PA_LOG_DEBUG))
- pa_log_debug("Next volume change in %lld usec", s->thread_info.volume_changes->at - now);
+ pa_log_debug("Next volume change in %lld usec", (long long) (s->thread_info.volume_changes->at - now));
}
else {
if (usec_to_next)
@@ -3008,7 +3240,7 @@ static void pa_sink_volume_change_rewind(pa_sink *s, size_t nbytes) {
pa_usec_t rewound = pa_bytes_to_usec(nbytes, &s->sample_spec);
pa_usec_t limit = pa_sink_get_latency_within_thread(s);
- pa_log_debug("latency = %lld", limit);
+ pa_log_debug("latency = %lld", (long long) limit);
limit += pa_rtclock_now() + s->thread_info.volume_change_extra_delay;
PA_LLIST_FOREACH(c, s->thread_info.volume_changes) {
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 4d569ddc..ef698813 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -44,6 +44,7 @@ typedef struct pa_sink_volume_change pa_sink_volume_change;
#include <pulsecore/card.h>
#include <pulsecore/queue.h>
#include <pulsecore/thread-mq.h>
+#include <pulsecore/sink-input.h>
#define PA_MAX_INPUTS_PER_SINK 32
@@ -86,6 +87,7 @@ struct pa_sink {
pa_idxset *inputs;
unsigned n_corked;
pa_source *monitor_source;
+ pa_sink_input *input_to_master; /* non-NULL only for filter sinks */
pa_volume_t base_volume; /* shall be constant */
unsigned n_volume_steps; /* shall be constant */
@@ -262,6 +264,7 @@ typedef enum pa_sink_message {
PA_SINK_MESSAGE_ADD_INPUT,
PA_SINK_MESSAGE_REMOVE_INPUT,
PA_SINK_MESSAGE_GET_VOLUME,
+ PA_SINK_MESSAGE_SET_SHARED_VOLUME,
PA_SINK_MESSAGE_SET_VOLUME_SYNCED,
PA_SINK_MESSAGE_SET_VOLUME,
PA_SINK_MESSAGE_SYNC_VOLUMES,
@@ -372,6 +375,9 @@ int pa_sink_update_status(pa_sink*s);
int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause);
int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause);
+/* Use this instead of checking s->flags & PA_SINK_FLAT_VOLUME directly. */
+pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s);
+
void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t sendmsg, pa_bool_t save);
const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh);
diff --git a/src/pulsecore/sndfile-util.c b/src/pulsecore/sndfile-util.c
index 9d15a868..292eb6e8 100644
--- a/src/pulsecore/sndfile-util.c
+++ b/src/pulsecore/sndfile-util.c
@@ -51,6 +51,9 @@ int pa_sndfile_read_sample_spec(SNDFILE *sf, pa_sample_spec *ss) {
break;
case SF_FORMAT_PCM_24:
+ ss->format = PA_SAMPLE_S24NE;
+ break;
+
case SF_FORMAT_PCM_32:
ss->format = PA_SAMPLE_S32NE;
break;
@@ -106,10 +109,14 @@ int pa_sndfile_write_sample_spec(SF_INFO *sfi, pa_sample_spec *ss) {
case PA_SAMPLE_S24LE:
case PA_SAMPLE_S24BE:
+ ss->format = PA_SAMPLE_S24NE;
+ sfi->format |= SF_FORMAT_PCM_24;
+ break;
+
case PA_SAMPLE_S24_32LE:
case PA_SAMPLE_S24_32BE:
- ss->format = PA_SAMPLE_S32NE;
- sfi->format |= SF_FORMAT_PCM_24;
+ ss->format = PA_SAMPLE_S24_32NE;
+ sfi->format |= SF_FORMAT_PCM_32;
break;
case PA_SAMPLE_S32LE:
@@ -297,8 +304,7 @@ int pa_sndfile_write_channel_map(SNDFILE *sf, pa_channel_map *cm) {
channels[c] = table[cm->map[c]];
}
- if (!sf_command(sf, SFC_SET_CHANNEL_MAP_INFO,
- channels, sizeof(channels[0]) * cm->channels)) {
+ if (!sf_command(sf, SFC_SET_CHANNEL_MAP_INFO, channels, sizeof(channels[0]) * cm->channels)) {
pa_xfree(channels);
return -1;
}
@@ -362,6 +368,7 @@ pa_sndfile_readf_t pa_sndfile_readf_function(const pa_sample_spec *ss) {
return (pa_sndfile_readf_t) sf_readf_short;
case PA_SAMPLE_S32NE:
+ case PA_SAMPLE_S24_32NE:
return (pa_sndfile_readf_t) sf_readf_int;
case PA_SAMPLE_FLOAT32NE:
@@ -384,6 +391,7 @@ pa_sndfile_writef_t pa_sndfile_writef_function(const pa_sample_spec *ss) {
return (pa_sndfile_writef_t) sf_writef_short;
case PA_SAMPLE_S32NE:
+ case PA_SAMPLE_S24_32NE:
return (pa_sndfile_writef_t) sf_writef_int;
case PA_SAMPLE_FLOAT32NE:
diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c
index 4037dca8..1ec19425 100644
--- a/src/pulsecore/sound-file-stream.c
+++ b/src/pulsecore/sound-file-stream.c
@@ -200,7 +200,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk
}
return -1;
- }
+}
static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
file_stream *u;
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 88731e76..0bb8899c 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -208,6 +208,7 @@ int pa_source_output_new(
o->driver = pa_xstrdup(pa_path_get_filename(data->driver));
o->module = data->module;
o->source = data->source;
+ o->destination_source = data->destination_source;
o->client = data->client;
o->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID;
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index 273b78fc..f16f9520 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -74,7 +74,8 @@ struct pa_source_output {
pa_module *module; /* may be NULL */
pa_client *client; /* may be NULL */
- pa_source *source; /* NULL while being moved */
+ pa_source *source; /* NULL while being moved */
+ pa_source *destination_source; /* only set by filter sources */
/* A source output can monitor just a single input of a sink, in which case we find it here */
pa_sink_input *direct_on_input; /* may be NULL */
@@ -211,6 +212,7 @@ typedef struct pa_source_output_new_data {
pa_client *client;
pa_source *source;
+ pa_source *destination_source;
pa_resample_method_t resample_method;
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 412a3db9..92fb80e0 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -221,6 +221,7 @@ pa_source* pa_source_new(
s->outputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
s->monitor_of = NULL;
+ s->output_from_master = NULL;
s->volume = data->volume;
pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
@@ -1401,22 +1402,22 @@ void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t
/* Called from main thread */
void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
- pa_source_assert_ref(s);
- pa_assert_ctl_context();
- pa_assert(min_latency);
- pa_assert(max_latency);
-
- if (PA_SOURCE_IS_LINKED(s->state)) {
- pa_usec_t r[2] = { 0, 0 };
-
- pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
-
- *min_latency = r[0];
- *max_latency = r[1];
- } else {
- *min_latency = s->thread_info.min_latency;
- *max_latency = s->thread_info.max_latency;
- }
+ pa_source_assert_ref(s);
+ pa_assert_ctl_context();
+ pa_assert(min_latency);
+ pa_assert(max_latency);
+
+ if (PA_SOURCE_IS_LINKED(s->state)) {
+ pa_usec_t r[2] = { 0, 0 };
+
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
+
+ *min_latency = r[0];
+ *max_latency = r[1];
+ } else {
+ *min_latency = s->thread_info.min_latency;
+ *max_latency = s->thread_info.max_latency;
+ }
}
/* Called from IO thread, and from main thread before pa_source_put() is called */
@@ -1570,5 +1571,7 @@ int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save) {
s->active_port = port;
s->save_port = save;
+ pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], s);
+
return 0;
}
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index e3e56bc4..9e8e2ada 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -75,6 +75,7 @@ struct pa_source {
pa_idxset *outputs;
unsigned n_corked;
pa_sink *monitor_of; /* may be NULL */
+ pa_source_output *output_from_master; /* non-NULL only for filter sources */
pa_volume_t base_volume; /* shall be constant */
unsigned n_volume_steps; /* shall be constant */
@@ -155,7 +156,7 @@ struct pa_source {
pa_usec_t max_latency; /* An upper limit for the latencies */
pa_usec_t fixed_latency; /* for sources with PA_SOURCE_DYNAMIC_LATENCY this is 0 */
- } thread_info;
+} thread_info;
void *userdata;
};
diff --git a/src/pulsecore/strbuf.c b/src/pulsecore/strbuf.c
index 4fc82ded..f131d5cd 100644
--- a/src/pulsecore/strbuf.c
+++ b/src/pulsecore/strbuf.c
@@ -146,7 +146,7 @@ void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) {
pa_assert(t);
if (!l)
- return;
+ return;
c = pa_xmalloc(PA_ALIGN(sizeof(struct chunk)) + l);
c->length = l;
diff --git a/src/pulsecore/strlist.c b/src/pulsecore/strlist.c
index 0f4ca867..b2ba12ba 100644
--- a/src/pulsecore/strlist.c
+++ b/src/pulsecore/strlist.c
@@ -49,7 +49,7 @@ pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s) {
memcpy(ITEM_TO_TEXT(n), s, size + 1);
n->next = l;
- return n;
+ return n;
}
char *pa_strlist_tostring(pa_strlist *l) {
diff --git a/src/pulsecore/svolume.orc b/src/pulsecore/svolume.orc
new file mode 100644
index 00000000..3411161c
--- /dev/null
+++ b/src/pulsecore/svolume.orc
@@ -0,0 +1,84 @@
+# This file is part of PulseAudio.
+#
+# Copyright 2010 Lennart Poettering
+# Copyright 2010 Wim Taymans <wim.taymans@collabora.co.uk>
+# Copyright 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
+#
+# PulseAudio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 of the License,
+# or (at your option) any later version.
+#
+# PulseAudio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with PulseAudio; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA.
+
+# S16NE 1- and 2-channel volume scaling work as follows:
+#
+# params: samples s (signed 16-bit), volume v (signed 32-bit < 2^31)
+#
+# 32 16 0 (type of operation)
+# sample = | sample | (signed)
+# s = | 0 | sample | (unsigned)
+#
+# if (sample < 0)
+# signc = | 0 | 0xffff | (unsigned)
+# else
+# signc = | 0 | 0 | (unsgined)
+#
+# if (sample < 0)
+# ml = | 0 | -((s*vl) >> 16) | (unsgined)
+# else
+# ml = | 0 | (s*vl) >> 16 | (unsgined)
+#
+# vh = | v >> 16 | (signed, but value is always signed
+# since PA_VOLUME_MAX is 0x0fffffff)
+# mh = | (s * vh) >> 16 | (signed)
+# ml = | ml + mh | (signed)
+# sample = | (ml >> 16) | (signed, saturated)
+
+.function pa_volume_s16ne_orc_1ch
+.dest 2 samples int16_t
+.param 4 v int32_t
+.temp 2 vh
+.temp 4 s
+.temp 4 mh
+.temp 4 ml
+.temp 4 signc
+
+convuwl s, samples
+x2 cmpgtsw signc, 0, s
+x2 andw signc, signc, v
+x2 mulhuw ml, s, v
+subl ml, ml, signc
+convhlw vh, v
+mulswl mh, samples, vh
+addl ml, ml, mh
+convssslw samples, ml
+
+.function pa_volume_s16ne_orc_2ch
+.dest 4 samples int16_t
+.longparam 8 vols
+.temp 8 v
+.temp 4 vh
+.temp 8 s
+.temp 8 mh
+.temp 8 ml
+.temp 8 signc
+
+loadpq v, vols
+x2 convuwl s, samples
+x4 cmpgtsw signc, 0, s
+x4 andw signc, signc, v
+x4 mulhuw ml, s, v
+x2 subl ml, ml, signc
+x2 convhlw vh, v
+x2 mulswl mh, samples, vh
+x2 addl ml, ml, mh
+x2 convssslw samples, ml
diff --git a/src/pulsecore/svolume_arm.c b/src/pulsecore/svolume_arm.c
index 3973e518..42e8cbf9 100644
--- a/src/pulsecore/svolume_arm.c
+++ b/src/pulsecore/svolume_arm.c
@@ -29,22 +29,21 @@
#include <pulsecore/macro.h>
#include <pulsecore/g711.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/endianmacros.h>
#include "cpu-arm.h"
#include "sample-util.h"
-#include "endianmacros.h"
#if defined (__arm__) && defined (HAVE_ARMV6)
#define MOD_INC() \
" subs r0, r6, %2 \n\t" \
+ " itt cs \n\t" \
" addcs r0, %1 \n\t" \
" movcs r6, r0 \n\t"
-static void
-pa_volume_s16ne_arm (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16ne_arm(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
int32_t *ve;
/* Channels must be at least 4, and always a multiple of the original number.
@@ -129,11 +128,11 @@ pa_volume_s16ne_arm (int16_t *samples, int32_t *volumes, unsigned channels, unsi
#ifdef RUN_TEST
#define CHANNELS 2
-#define SAMPLES 1023
+#define SAMPLES 1022
#define TIMES 1000
#define PADDING 16
-static void run_test (void) {
+static void run_test(void) {
int16_t samples[SAMPLES];
int16_t samples_ref[SAMPLES];
int16_t samples_orig[SAMPLES];
@@ -142,21 +141,21 @@ static void run_test (void) {
pa_do_volume_func_t func;
pa_usec_t start, stop;
- func = pa_get_volume_func (PA_SAMPLE_S16NE);
+ func = pa_get_volume_func(PA_SAMPLE_S16NE);
- printf ("checking ARM %zd\n", sizeof (samples));
+ printf("checking ARM %zd\n", sizeof(samples));
- pa_random (samples, sizeof (samples));
- memcpy (samples_ref, samples, sizeof (samples));
- memcpy (samples_orig, samples, sizeof (samples));
+ pa_random(samples, sizeof(samples));
+ memcpy(samples_ref, samples, sizeof(samples));
+ memcpy(samples_orig, samples, sizeof(samples));
for (i = 0; i < CHANNELS; i++)
- volumes[i] = rand() >> 1;
+ volumes[i] = PA_CLAMP_VOLUME(rand() >> 1);
for (padding = 0; padding < PADDING; padding++, i++)
volumes[i] = volumes[padding];
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
- pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples));
+ func(samples_ref, volumes, CHANNELS, sizeof(samples));
+ pa_volume_s16ne_arm(samples, volumes, CHANNELS, sizeof(samples));
for (i = 0; i < SAMPLES; i++) {
if (samples[i] != samples_ref[i]) {
printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i],
@@ -166,16 +165,16 @@ static void run_test (void) {
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples, samples_orig, sizeof (samples));
- pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples, samples_orig, sizeof(samples));
+ pa_volume_s16ne_arm(samples, volumes, CHANNELS, sizeof(samples));
}
stop = pa_rtclock_now();
pa_log_info("ARM: %llu usec.", (long long unsigned int) (stop - start));
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples_ref, samples_orig, sizeof (samples));
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples_ref, samples_orig, sizeof(samples));
+ func(samples_ref, volumes, CHANNELS, sizeof(samples));
}
stop = pa_rtclock_now();
pa_log_info("ref: %llu usec.", (long long unsigned int) (stop - start));
@@ -185,14 +184,14 @@ static void run_test (void) {
#endif /* defined (__arm__) && defined (HAVE_ARMV6) */
-void pa_volume_func_init_arm (pa_cpu_arm_flag_t flags) {
+void pa_volume_func_init_arm(pa_cpu_arm_flag_t flags) {
#if defined (__arm__) && defined (HAVE_ARMV6)
pa_log_info("Initialising ARM optimized functions.");
#ifdef RUN_TEST
- run_test ();
+ run_test();
#endif
- pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_arm);
+ pa_set_volume_func(PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_arm);
#endif /* defined (__arm__) && defined (HAVE_ARMV6) */
}
diff --git a/src/pulsecore/svolume_c.c b/src/pulsecore/svolume_c.c
index 5fc052b8..e55d0d7b 100644
--- a/src/pulsecore/svolume_c.c
+++ b/src/pulsecore/svolume_c.c
@@ -28,13 +28,11 @@
#include <pulsecore/macro.h>
#include <pulsecore/g711.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/endianmacros.h>
#include "sample-util.h"
-#include "endianmacros.h"
-static void
-pa_volume_u8_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_u8_c(uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
for (channel = 0; length; length--) {
@@ -53,9 +51,7 @@ pa_volume_u8_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned
}
}
-static void
-pa_volume_alaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_alaw_c(uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
for (channel = 0; length; length--) {
@@ -74,9 +70,7 @@ pa_volume_alaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigne
}
}
-static void
-pa_volume_ulaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_ulaw_c(uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
for (channel = 0; length; length--) {
@@ -95,12 +89,10 @@ pa_volume_ulaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigne
}
}
-static void
-pa_volume_s16ne_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16ne_c(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (int16_t);
+ length /= sizeof(int16_t);
for (channel = 0; length; length--) {
int32_t t, hi, lo;
@@ -124,12 +116,10 @@ pa_volume_s16ne_c (int16_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s16re_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16re_c(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (int16_t);
+ length /= sizeof(int16_t);
for (channel = 0; length; length--) {
int32_t t, hi, lo;
@@ -147,12 +137,10 @@ pa_volume_s16re_c (int16_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_float32ne_c (float *samples, float *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_float32ne_c(float *samples, float *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (float);
+ length /= sizeof(float);
for (channel = 0; length; length--) {
*samples++ *= volumes[channel];
@@ -162,12 +150,10 @@ pa_volume_float32ne_c (float *samples, float *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_float32re_c (float *samples, float *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_float32re_c(float *samples, float *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (float);
+ length /= sizeof(float);
for (channel = 0; length; length--) {
float t;
@@ -181,12 +167,10 @@ pa_volume_float32re_c (float *samples, float *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s32ne_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s32ne_c(int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (int32_t);
+ length /= sizeof(int32_t);
for (channel = 0; length; length--) {
int64_t t;
@@ -201,12 +185,10 @@ pa_volume_s32ne_c (int32_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s32re_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s32re_c(int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (int32_t);
+ length /= sizeof(int32_t);
for (channel = 0; length; length--) {
int64_t t;
@@ -221,9 +203,7 @@ pa_volume_s32re_c (int32_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s24ne_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s24ne_c(uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
uint8_t *e;
@@ -242,9 +222,7 @@ pa_volume_s24ne_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s24re_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s24re_c(uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
uint8_t *e;
@@ -263,12 +241,10 @@ pa_volume_s24re_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsign
}
}
-static void
-pa_volume_s24_32ne_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s24_32ne_c(uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (uint32_t);
+ length /= sizeof(uint32_t);
for (channel = 0; length; length--) {
int64_t t;
@@ -283,12 +259,10 @@ pa_volume_s24_32ne_c (uint32_t *samples, int32_t *volumes, unsigned channels, un
}
}
-static void
-pa_volume_s24_32re_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s24_32re_c(uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
unsigned channel;
- length /= sizeof (uint32_t);
+ length /= sizeof(uint32_t);
for (channel = 0; length; length--) {
int64_t t;
@@ -303,8 +277,7 @@ pa_volume_s24_32re_c (uint32_t *samples, int32_t *volumes, unsigned channels, un
}
}
-static pa_do_volume_func_t do_volume_table[] =
-{
+static pa_do_volume_func_t do_volume_table[] = {
[PA_SAMPLE_U8] = (pa_do_volume_func_t) pa_volume_u8_c,
[PA_SAMPLE_ALAW] = (pa_do_volume_func_t) pa_volume_alaw_c,
[PA_SAMPLE_ULAW] = (pa_do_volume_func_t) pa_volume_ulaw_c,
diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c
index 3e2992a2..421156ea 100644
--- a/src/pulsecore/svolume_mmx.c
+++ b/src/pulsecore/svolume_mmx.c
@@ -31,11 +31,11 @@
#include <pulsecore/macro.h>
#include <pulsecore/g711.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/endianmacros.h>
#include "cpu-x86.h"
#include "sample-util.h"
-#include "endianmacros.h"
#if defined (__i386__) || defined (__amd64__)
/* in s: 2 int16_t samples
@@ -95,9 +95,7 @@
" por %%mm4, "#s1" \n\t" /* .. | l h | */ \
" por %%mm5, "#s2" \n\t"
-static void
-pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16ne_mmx(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
pa_reg_x86 channel, temp;
/* Channels must be at least 4, and always a multiple of the original number.
@@ -156,15 +154,13 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi
"6: \n\t"
" emms \n\t"
- : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((pa_reg_x86)channel), "=&r" (temp)
+ : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp)
: "rm" ((pa_reg_x86)channels)
: "cc"
);
}
-static void
-pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16re_mmx(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
pa_reg_x86 channel, temp;
/* Channels must be at least 4, and always a multiple of the original number.
@@ -233,7 +229,7 @@ pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi
"6: \n\t"
" emms \n\t"
- : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((pa_reg_x86)channel), "=&r" (temp)
+ : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp)
: "rm" ((pa_reg_x86)channels)
: "cc"
);
@@ -243,11 +239,11 @@ pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi
#ifdef RUN_TEST
#define CHANNELS 2
-#define SAMPLES 1021
+#define SAMPLES 1022
#define TIMES 1000
#define PADDING 16
-static void run_test (void) {
+static void run_test(void) {
int16_t samples[SAMPLES];
int16_t samples_ref[SAMPLES];
int16_t samples_orig[SAMPLES];
@@ -256,43 +252,43 @@ static void run_test (void) {
pa_do_volume_func_t func;
pa_usec_t start, stop;
- func = pa_get_volume_func (PA_SAMPLE_S16NE);
+ func = pa_get_volume_func(PA_SAMPLE_S16NE);
- printf ("checking MMX %zd\n", sizeof (samples));
+ printf("checking MMX %zd\n", sizeof(samples));
- pa_random (samples, sizeof (samples));
+ pa_random(samples, sizeof(samples));
/* for (i = 0; i < SAMPLES; i++)
samples[i] = -1; */
- memcpy (samples_ref, samples, sizeof (samples));
- memcpy (samples_orig, samples, sizeof (samples));
+ memcpy(samples_ref, samples, sizeof(samples));
+ memcpy(samples_orig, samples, sizeof(samples));
for (i = 0; i < CHANNELS; i++)
- volumes[i] = rand() >> 1;
+ volumes[i] = PA_CLAMP_VOLUME(rand() >> 1);
/* volumes[i] = 0x0000ffff; */
for (padding = 0; padding < PADDING; padding++, i++)
volumes[i] = volumes[padding];
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
- pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples));
+ func(samples_ref, volumes, CHANNELS, sizeof(samples));
+ pa_volume_s16ne_mmx(samples, volumes, CHANNELS, sizeof(samples));
for (i = 0; i < SAMPLES; i++) {
if (samples[i] != samples_ref[i]) {
- printf ("%d: %04x != %04x (%04x * %08x)\n", i, samples[i], samples_ref[i],
+ printf("%d: %04x != %04x (%04x * %08x)\n", i, samples[i], samples_ref[i],
samples_orig[i], volumes[i % CHANNELS]);
}
}
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples, samples_orig, sizeof (samples));
- pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples, samples_orig, sizeof(samples));
+ pa_volume_s16ne_mmx(samples, volumes, CHANNELS, sizeof(samples));
}
stop = pa_rtclock_now();
pa_log_info("MMX: %llu usec.", (long long unsigned int)(stop - start));
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples_ref, samples_orig, sizeof (samples));
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples_ref, samples_orig, sizeof(samples));
+ func(samples_ref, volumes, CHANNELS, sizeof(samples));
}
stop = pa_rtclock_now();
pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start));
@@ -304,18 +300,18 @@ static void run_test (void) {
#endif /* defined (__i386__) || defined (__amd64__) */
-void pa_volume_func_init_mmx (pa_cpu_x86_flag_t flags) {
+void pa_volume_func_init_mmx(pa_cpu_x86_flag_t flags) {
#if defined (__i386__) || defined (__amd64__)
#ifdef RUN_TEST
- run_test ();
+ run_test();
#endif
if ((flags & PA_CPU_X86_MMX) && (flags & PA_CPU_X86_CMOV)) {
pa_log_info("Initialising MMX optimized functions.");
- pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_mmx);
- pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_mmx);
+ pa_set_volume_func(PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_mmx);
+ pa_set_volume_func(PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_mmx);
}
#endif /* defined (__i386__) || defined (__amd64__) */
}
diff --git a/src/pulsecore/svolume_orc.c b/src/pulsecore/svolume_orc.c
new file mode 100644
index 00000000..db07ba61
--- /dev/null
+++ b/src/pulsecore/svolume_orc.c
@@ -0,0 +1,117 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2004-2006 Lennart Poettering
+ Copyright 2009 Wim Taymans <wim.taymans@collabora.co.uk>
+ Copyright 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "cpu-orc.h"
+#include <pulse/xmalloc.h>
+#include <pulse/rtclock.h>
+#include <pulsecore/sample-util.h>
+#include <pulsecore/random.h>
+#include <pulsecore/svolume-orc-gen.h>
+
+pa_do_volume_func_t fallback;
+
+static void
+pa_volume_s16ne_orc(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
+{
+ if (channels == 2) {
+ int64_t v = (int64_t)volumes[1] << 32 | volumes[0];
+ pa_volume_s16ne_orc_2ch (samples, v, ((length / (sizeof(int16_t))) / 2));
+ } else if (channels == 1)
+ pa_volume_s16ne_orc_1ch (samples, volumes[0], length / (sizeof(int16_t)));
+ else
+ fallback(samples, volumes, channels, length);
+}
+
+#undef RUN_TEST
+
+#ifdef RUN_TEST
+#define CHANNELS 2
+#define SAMPLES 1022
+#define TIMES 1000
+#define PADDING 16
+
+static void run_test (void) {
+ int16_t samples[SAMPLES];
+ int16_t samples_ref[SAMPLES];
+ int16_t samples_orig[SAMPLES];
+ int32_t volumes[CHANNELS + PADDING];
+ int i, j, padding;
+ pa_do_volume_func_t func;
+ pa_usec_t start, stop;
+
+ func = pa_get_volume_func (PA_SAMPLE_S16NE);
+
+ printf ("checking ORC %zd\n", sizeof (samples));
+
+ pa_random (samples, sizeof (samples));
+ memcpy (samples_ref, samples, sizeof (samples));
+ memcpy (samples_orig, samples, sizeof (samples));
+
+ for (i = 0; i < CHANNELS; i++)
+ volumes[i] = PA_CLAMP_VOLUME(rand() >> 1);
+ for (padding = 0; padding < PADDING; padding++, i++)
+ volumes[i] = volumes[padding];
+
+ func (samples_ref, volumes, CHANNELS, sizeof (samples));
+ pa_volume_s16ne_orc (samples, volumes, CHANNELS, sizeof (samples));
+ for (i = 0; i < SAMPLES; i++) {
+ if (samples[i] != samples_ref[i]) {
+ printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i],
+ samples_orig[i], volumes[i % CHANNELS]);
+ }
+ }
+
+ start = pa_rtclock_now();
+ for (j = 0; j < TIMES; j++) {
+ memcpy (samples, samples_orig, sizeof (samples));
+ pa_volume_s16ne_orc (samples, volumes, CHANNELS, sizeof (samples));
+ }
+ stop = pa_rtclock_now();
+ pa_log_info("ORC: %llu usec.", (long long unsigned int)(stop - start));
+
+ start = pa_rtclock_now();
+ for (j = 0; j < TIMES; j++) {
+ memcpy (samples_ref, samples_orig, sizeof (samples));
+ func (samples_ref, volumes, CHANNELS, sizeof (samples));
+ }
+ stop = pa_rtclock_now();
+ pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start));
+
+ pa_assert_se(memcmp(samples_ref, samples, sizeof(samples)) == 0);
+}
+#endif
+
+void pa_volume_func_init_orc(void) {
+ pa_log_info("Initialising ORC optimized functions.");
+
+#ifdef RUN_TEST
+ run_test();
+#endif
+
+ fallback = pa_get_volume_func(PA_SAMPLE_S16NE);
+ pa_set_volume_func(PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_orc);
+}
diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c
index 200482ec..ef07a243 100644
--- a/src/pulsecore/svolume_sse.c
+++ b/src/pulsecore/svolume_sse.c
@@ -31,11 +31,11 @@
#include <pulsecore/macro.h>
#include <pulsecore/g711.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/endianmacros.h>
#include "cpu-x86.h"
#include "sample-util.h"
-#include "endianmacros.h"
#if defined (__i386__) || defined (__amd64__)
@@ -79,9 +79,7 @@
static int channel_overread_table[8] = {8,8,8,12,8,10,12,14};
-static void
-pa_volume_s16ne_sse2 (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16ne_sse2(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
pa_reg_x86 channel, temp;
/* Channels must be at least 8 and always a multiple of the original number.
@@ -161,9 +159,7 @@ pa_volume_s16ne_sse2 (int16_t *samples, int32_t *volumes, unsigned channels, uns
);
}
-static void
-pa_volume_s16re_sse2 (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length)
-{
+static void pa_volume_s16re_sse2(int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) {
pa_reg_x86 channel, temp;
/* Channels must be at least 8 and always a multiple of the original number.
@@ -255,11 +251,11 @@ pa_volume_s16re_sse2 (int16_t *samples, int32_t *volumes, unsigned channels, uns
#ifdef RUN_TEST
#define CHANNELS 2
-#define SAMPLES 1021
+#define SAMPLES 1022
#define TIMES 1000
#define PADDING 16
-static void run_test (void) {
+static void run_test(void) {
int16_t samples[SAMPLES];
int16_t samples_ref[SAMPLES];
int16_t samples_orig[SAMPLES];
@@ -268,21 +264,21 @@ static void run_test (void) {
pa_do_volume_func_t func;
pa_usec_t start, stop;
- func = pa_get_volume_func (PA_SAMPLE_S16NE);
+ func = pa_get_volume_func(PA_SAMPLE_S16NE);
- printf ("checking SSE2 %zd\n", sizeof (samples));
+ printf("checking SSE2 %zd\n", sizeof(samples));
- pa_random (samples, sizeof (samples));
- memcpy (samples_ref, samples, sizeof (samples));
- memcpy (samples_orig, samples, sizeof (samples));
+ pa_random(samples, sizeof(samples));
+ memcpy(samples_ref, samples, sizeof(samples));
+ memcpy(samples_orig, samples, sizeof(samples));
for (i = 0; i < CHANNELS; i++)
- volumes[i] = rand() >> 1;
+ volumes[i] = PA_CLAMP_VOLUME(rand() >> 1);
for (padding = 0; padding < PADDING; padding++, i++)
volumes[i] = volumes[padding];
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
- pa_volume_s16ne_sse2 (samples, volumes, CHANNELS, sizeof (samples));
+ func(samples_ref, volumes, CHANNELS, sizeof(samples));
+ pa_volume_s16ne_sse2(samples, volumes, CHANNELS, sizeof(samples));
for (i = 0; i < SAMPLES; i++) {
if (samples[i] != samples_ref[i]) {
printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i],
@@ -292,16 +288,16 @@ static void run_test (void) {
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples, samples_orig, sizeof (samples));
- pa_volume_s16ne_sse2 (samples, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples, samples_orig, sizeof(samples));
+ pa_volume_s16ne_sse2(samples, volumes, CHANNELS, sizeof(samples));
}
stop = pa_rtclock_now();
pa_log_info("SSE: %llu usec.", (long long unsigned int)(stop - start));
start = pa_rtclock_now();
for (j = 0; j < TIMES; j++) {
- memcpy (samples_ref, samples_orig, sizeof (samples));
- func (samples_ref, volumes, CHANNELS, sizeof (samples));
+ memcpy(samples_ref, samples_orig, sizeof(samples));
+ func(samples_ref, volumes, CHANNELS, sizeof (samples));
}
stop = pa_rtclock_now();
pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start));
@@ -311,18 +307,18 @@ static void run_test (void) {
#endif
#endif /* defined (__i386__) || defined (__amd64__) */
-void pa_volume_func_init_sse (pa_cpu_x86_flag_t flags) {
+void pa_volume_func_init_sse(pa_cpu_x86_flag_t flags) {
#if defined (__i386__) || defined (__amd64__)
#ifdef RUN_TEST
- run_test ();
+ run_test();
#endif
if (flags & PA_CPU_X86_SSE2) {
pa_log_info("Initialising SSE2 optimized functions.");
- pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse2);
- pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse2);
+ pa_set_volume_func(PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse2);
+ pa_set_volume_func(PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse2);
}
#endif /* defined (__i386__) || defined (__amd64__) */
}
diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c
index 0696cabc..a8dd333f 100644
--- a/src/pulsecore/time-smoother.c
+++ b/src/pulsecore/time-smoother.c
@@ -385,7 +385,7 @@ void pa_smoother_put(pa_smoother *s, pa_usec_t x, pa_usec_t y) {
s->abc_valid = FALSE;
#ifdef DEBUG_DATA
- pa_log_debug("%p, put(%llu | %llu) = %llu", s, (unsigned long long) (x + s->time_offset), (unsigned long long) x, (unsigned long long) y);
+ pa_log_debug("%p, put(%llu | %llu) = %llu", s, (unsigned long long) (x + s->time_offset), (unsigned long long) x, (unsigned long long) y);
#endif
}
@@ -441,7 +441,7 @@ void pa_smoother_pause(pa_smoother *s, pa_usec_t x) {
return;
#ifdef DEBUG_DATA
- pa_log_debug("pause(%llu)", (unsigned long long) x);
+ pa_log_debug("pause(%llu)", (unsigned long long) x);
#endif
s->paused = TRUE;
diff --git a/src/pulsecore/usergroup.c b/src/pulsecore/usergroup.c
index 71b13bca..c244865e 100644
--- a/src/pulsecore/usergroup.c
+++ b/src/pulsecore/usergroup.c
@@ -142,9 +142,7 @@ struct group *pa_getgrgid_malloc(gid_t gid) {
getgr_buflen = buflen - sizeof(struct group);
getgr_buf = (char *)buf + sizeof(struct group);
- while ((err = getgrgid_r(gid, (struct group *)buf, getgr_buf,
- getgr_buflen, &result)) == ERANGE)
- {
+ while ((err = getgrgid_r(gid, (struct group *)buf, getgr_buf, getgr_buflen, &result)) == ERANGE) {
if (expand_buffer_trashcontents(&buf, &buflen))
break;
@@ -203,9 +201,7 @@ struct group *pa_getgrnam_malloc(const char *name) {
getgr_buflen = buflen - sizeof(struct group);
getgr_buf = (char *)buf + sizeof(struct group);
- while ((err = getgrnam_r(name, (struct group *)buf, getgr_buf,
- getgr_buflen, &result)) == ERANGE)
- {
+ while ((err = getgrnam_r(name, (struct group *)buf, getgr_buf, getgr_buflen, &result)) == ERANGE) {
if (expand_buffer_trashcontents(&buf, &buflen))
break;
@@ -268,9 +264,7 @@ struct passwd *pa_getpwnam_malloc(const char *name) {
getpw_buflen = buflen - sizeof(struct passwd);
getpw_buf = (char *)buf + sizeof(struct passwd);
- while ((err = getpwnam_r(name, (struct passwd *)buf, getpw_buf,
- getpw_buflen, &result)) == ERANGE)
- {
+ while ((err = getpwnam_r(name, (struct passwd *)buf, getpw_buf, getpw_buflen, &result)) == ERANGE) {
if (expand_buffer_trashcontents(&buf, &buflen))
break;
@@ -329,9 +323,7 @@ struct passwd *pa_getpwuid_malloc(uid_t uid) {
getpw_buflen = buflen - sizeof(struct passwd);
getpw_buf = (char *)buf + sizeof(struct passwd);
- while ((err = getpwuid_r(uid, (struct passwd *)buf, getpw_buf,
- getpw_buflen, &result)) == ERANGE)
- {
+ while ((err = getpwuid_r(uid, (struct passwd *)buf, getpw_buf, getpw_buflen, &result)) == ERANGE) {
if (expand_buffer_trashcontents(&buf, &buflen))
break;
diff --git a/src/pulsecore/x11prop.c b/src/pulsecore/x11prop.c
index 4cb21daa..8df32788 100644
--- a/src/pulsecore/x11prop.c
+++ b/src/pulsecore/x11prop.c
@@ -34,8 +34,7 @@
#define PA_XCB_FORMAT 8
-static xcb_screen_t *screen_of_display(xcb_connection_t *xcb, int screen)
-{
+static xcb_screen_t *screen_of_display(xcb_connection_t *xcb, int screen) {
const xcb_setup_t *s;
xcb_screen_iterator_t iter;
diff --git a/src/tests/cpulimit-test.c b/src/tests/cpulimit-test.c
index 9d0f4eef..5b11bc44 100644
--- a/src/tests/cpulimit-test.c
+++ b/src/tests/cpulimit-test.c
@@ -22,7 +22,7 @@
#endif
#include <assert.h>
-#include <sys/time.h>
+#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
@@ -34,7 +34,7 @@
#include <pulse/mainloop-signal.h>
#endif
-#include "../daemon/cpulimit.h"
+#include <daemon/cpulimit.h>
/* A simple example for testing the cpulimit subsystem */
diff --git a/src/tests/envelope-test.c b/src/tests/envelope-test.c
deleted file mode 100644
index 9382040b..00000000
--- a/src/tests/envelope-test.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/***
- This file is part of PulseAudio.
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <pulse/sample.h>
-#include <pulse/volume.h>
-#include <pulse/timeval.h>
-
-#include <pulsecore/envelope.h>
-#include <pulsecore/macro.h>
-#include <pulsecore/endianmacros.h>
-#include <pulsecore/memblock.h>
-#include <pulsecore/sample-util.h>
-
-const pa_envelope_def ramp_down = {
- .n_points = 2,
- .points_x = { 100*PA_USEC_PER_MSEC, 300*PA_USEC_PER_MSEC },
- .points_y = {
- .f = { 1.0f, 0.2f },
- .i = { 0x10000, 0x10000/5 }
- }
-};
-
-const pa_envelope_def ramp_up = {
- .n_points = 2,
- .points_x = { 100*PA_USEC_PER_MSEC, 300*PA_USEC_PER_MSEC },
- .points_y = {
- .f = { 0.2f, 1.0f },
- .i = { 0x10000/5, 0x10000 }
- }
-};
-
-const pa_envelope_def ramp_down2 = {
- .n_points = 2,
- .points_x = { 50*PA_USEC_PER_MSEC, 900*PA_USEC_PER_MSEC },
- .points_y = {
- .f = { 0.8f, 0.7f },
- .i = { 0x10000*4/5, 0x10000*7/10 }
- }
-};
-
-const pa_envelope_def ramp_up2 = {
- .n_points = 2,
- .points_x = { 50*PA_USEC_PER_MSEC, 900*PA_USEC_PER_MSEC },
- .points_y = {
- .f = { 0.7f, 0.9f },
- .i = { 0x10000*7/10, 0x10000*9/10 }
- }
-};
-
-static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) {
- void *d;
- unsigned i;
-
- static unsigned j = 0;
-
- d = pa_memblock_acquire(chunk->memblock);
-
- switch (ss->format) {
-
- case PA_SAMPLE_U8:
- case PA_SAMPLE_ULAW:
- case PA_SAMPLE_ALAW: {
- uint8_t *u = d;
-
- for (i = 0; i < chunk->length / pa_frame_size(ss); i++)
- printf("0x%02x ", *(u++));
-
- break;
- }
-
- case PA_SAMPLE_S16NE:
- case PA_SAMPLE_S16RE: {
- int16_t *u = d;
-
- for (i = 0; i < chunk->length / pa_frame_size(ss); i++)
- printf("%i\t%i\n", j++, *(u++));
-
- break;
- }
-
- case PA_SAMPLE_S32NE:
- case PA_SAMPLE_S32RE: {
- int32_t *u = d;
-
- for (i = 0; i < chunk->length / pa_frame_size(ss); i++)
- printf("%i\t%i\n", j++, *(u++));
-
- break;
- }
-
- case PA_SAMPLE_FLOAT32NE:
- case PA_SAMPLE_FLOAT32RE: {
- float *u = d;
-
- for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
- printf("%i\t%1.3g\n", j++, PA_MAYBE_FLOAT32_SWAP(ss->format == PA_SAMPLE_FLOAT32RE, *u));
- u++;
- }
-
- break;
- }
-
- default:
- pa_assert_not_reached();
- }
-
- printf("\n");
-
- pa_memblock_release(chunk->memblock);
-}
-
-static pa_memblock * generate_block(pa_mempool *pool, const pa_sample_spec *ss) {
- pa_memblock *block;
- void *d;
- unsigned n_samples;
-
- block = pa_memblock_new(pool, pa_bytes_per_second(ss));
- n_samples = (unsigned) (pa_memblock_get_length(block) / pa_sample_size(ss));
-
- d = pa_memblock_acquire(block);
-
- switch (ss->format) {
-
- case PA_SAMPLE_S16NE:
- case PA_SAMPLE_S16RE: {
- int16_t *i;
-
- for (i = d; n_samples > 0; n_samples--, i++)
- *i = 0x7FFF;
-
- break;
- }
-
- case PA_SAMPLE_S32NE:
- case PA_SAMPLE_S32RE: {
- int32_t *i;
-
- for (i = d; n_samples > 0; n_samples--, i++)
- *i = 0x7FFFFFFF;
-
- break;
- }
-
- case PA_SAMPLE_FLOAT32RE:
- case PA_SAMPLE_FLOAT32NE: {
- float *f;
-
- for (f = d; n_samples > 0; n_samples--, f++)
- *f = PA_MAYBE_FLOAT32_SWAP(ss->format == PA_SAMPLE_FLOAT32RE, 1.0f);
-
- break;
- }
-
- default:
- pa_assert_not_reached();
- }
-
- pa_memblock_release(block);
- return block;
-}
-
-int main(int argc, char *argv[]) {
- pa_mempool *pool;
- pa_memblock *block;
- pa_memchunk chunk;
- pa_envelope *envelope;
- pa_envelope_item *item1, *item2;
-
- const pa_sample_spec ss = {
- .format = PA_SAMPLE_S16NE,
- .channels = 1,
- .rate = 200
- };
-
- const pa_cvolume v = {
- .channels = 1,
- .values = { PA_VOLUME_NORM, PA_VOLUME_NORM/2 }
- };
-
- pa_log_set_level(PA_LOG_DEBUG);
-
- pa_assert_se(pool = pa_mempool_new(FALSE, 0));
- pa_assert_se(envelope = pa_envelope_new(&ss));
-
- block = generate_block(pool, &ss);
-
- chunk.memblock = pa_memblock_ref(block);
- chunk.length = pa_memblock_get_length(block);
- chunk.index = 0;
-
- pa_volume_memchunk(&chunk, &ss, &v);
-
- item1 = pa_envelope_add(envelope, &ramp_down);
- item2 = pa_envelope_add(envelope, &ramp_down2);
- pa_envelope_apply(envelope, &chunk);
- dump_block(&ss, &chunk);
-
- pa_memblock_unref(chunk.memblock);
-
- chunk.memblock = pa_memblock_ref(block);
- chunk.length = pa_memblock_get_length(block);
- chunk.index = 0;
-
- item1 = pa_envelope_replace(envelope, item1, &ramp_up);
- item2 = pa_envelope_replace(envelope, item2, &ramp_up2);
- pa_envelope_apply(envelope, &chunk);
- dump_block(&ss, &chunk);
-
- pa_memblock_unref(chunk.memblock);
-
- pa_envelope_remove(envelope, item1);
- pa_envelope_remove(envelope, item2);
- pa_envelope_free(envelope);
-
- pa_memblock_unref(block);
-
- pa_mempool_free(pool);
-
- return 0;
-}
diff --git a/src/tests/mainloop-test.c b/src/tests/mainloop-test.c
index 3ec6d115..cd54bcfe 100644
--- a/src/tests/mainloop-test.c
+++ b/src/tests/mainloop-test.c
@@ -48,7 +48,7 @@ static pa_defer_event *de;
static void iocb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
unsigned char c;
- (void) read(fd, &c, sizeof(c));
+ pa_assert_se(read(fd, &c, sizeof(c)) >= 0);
fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c);
a->defer_enable(de, 1);
}
diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c
index e401bb62..b6c60039 100644
--- a/src/tests/memblockq-test.c
+++ b/src/tests/memblockq-test.c
@@ -81,7 +81,7 @@ int main(int argc, char *argv[]) {
p = pa_mempool_new(FALSE, 0);
- silence.memblock = pa_memblock_new_fixed(p, (char*) "__", 2, 1);
+ silence.memblock = pa_memblock_new_fixed(p, (char*) "__", 2, 1);
assert(silence.memblock);
silence.index = 0;
silence.length = pa_memblock_get_length(silence.memblock);
diff --git a/src/tests/mix-test.c b/src/tests/mix-test.c
index 457c4acd..55844e7f 100644
--- a/src/tests/mix-test.c
+++ b/src/tests/mix-test.c
@@ -32,12 +32,6 @@
#include <pulsecore/memblock.h>
#include <pulsecore/sample-util.h>
-static float swap_float(float a) {
- uint32_t *b = (uint32_t*) &a;
- *b = PA_UINT32_SWAP(*b);
- return a;
-}
-
static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) {
void *d;
unsigned i;
@@ -96,7 +90,7 @@ static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) {
float *u = d;
for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
- printf("%1.5f ", ss->format == PA_SAMPLE_FLOAT32NE ? *u : swap_float(*u));
+ printf("%1.5f ", ss->format == PA_SAMPLE_FLOAT32NE ? *u : PA_FLOAT32_SWAP(*u));
u++;
}
@@ -188,7 +182,7 @@ static pa_memblock* generate_block(pa_mempool *pool, const pa_sample_spec *ss) {
if (ss->format == PA_SAMPLE_FLOAT32RE) {
for (i = 0; i < 10; i++)
- u[i] = swap_float(float_samples[i]);
+ u[i] = PA_FLOAT32_SWAP(float_samples[i]);
} else
memcpy(d, float_samples, sizeof(float_samples));
diff --git a/src/tests/rtstutter.c b/src/tests/rtstutter.c
index 9ef835c3..402a8c09 100644
--- a/src/tests/rtstutter.c
+++ b/src/tests/rtstutter.c
@@ -106,7 +106,7 @@ int main(int argc, char*argv[]) {
pa_assert(msec_upper > 0);
pa_assert(msec_upper >= msec_lower);
- pa_log_notice("Creating random latencies in the range of %ims to %ims.", msec_lower, msec_upper);
+ pa_log_notice("Creating random latencies in the range of %ims to %ims.", msec_lower, msec_upper);
for (n = 1; n < pa_ncpus(); n++) {
pa_assert_se(pa_thread_new("rtstutter", work, PA_UINT_TO_PTR(n)));
diff --git a/src/tests/usergroup-test.c b/src/tests/usergroup-test.c
index a48b016d..3948e0f8 100644
--- a/src/tests/usergroup-test.c
+++ b/src/tests/usergroup-test.c
@@ -47,28 +47,24 @@ static int compare_group(const struct group *a, const struct group *b) {
char **amem, **bmem;
if (strcmp(a->gr_name, b->gr_name)) {
- fprintf(stderr, "Group name mismatch: [%s] [%s]\n",
- a->gr_name, b->gr_name);
+ fprintf(stderr, "Group name mismatch: [%s] [%s]\n", a->gr_name, b->gr_name);
return 1;
}
if (strcmp(a->gr_passwd, b->gr_passwd)) {
- fprintf(stderr, "Group password mismatch: [%s] [%s]\n",
- a->gr_passwd, b->gr_passwd);
+ fprintf(stderr, "Group password mismatch: [%s] [%s]\n", a->gr_passwd, b->gr_passwd);
return 1;
}
if (a->gr_gid != b->gr_gid) {
- fprintf(stderr, "Gid mismatch: [%lu] [%lu]\n",
- (unsigned long) a->gr_gid, (unsigned long) b->gr_gid);
+ fprintf(stderr, "Gid mismatch: [%lu] [%lu]\n", (unsigned long) a->gr_gid, (unsigned long) b->gr_gid);
return 1;
}
/* XXX: Assuming the group ordering is identical. */
for (amem = a->gr_mem, bmem = b->gr_mem; *amem && *bmem; ++amem, ++bmem) {
if (strcmp(*amem, *bmem)) {
- fprintf(stderr, "Group member mismatch: [%s] [%s]\n",
- *amem, *bmem);
+ fprintf(stderr, "Group member mismatch: [%s] [%s]\n", *amem, *bmem);
return 1;
}
}
@@ -93,14 +89,12 @@ static int compare_passwd(const struct passwd *a, const struct passwd *b) {
}
if (a->pw_uid != b->pw_uid) {
- fprintf(stderr, "pw_uid mismatch: [%lu] [%lu]\n",
- (unsigned long) a->pw_uid, (unsigned long) b->pw_uid);
+ fprintf(stderr, "pw_uid mismatch: [%lu] [%lu]\n", (unsigned long) a->pw_uid, (unsigned long) b->pw_uid);
return 1;
}
if (a->pw_gid != b->pw_gid) {
- fprintf(stderr, "pw_gid mismatch: [%lu] [%lu]\n",
- (unsigned long) a->pw_gid, (unsigned long) b->pw_gid);
+ fprintf(stderr, "pw_gid mismatch: [%lu] [%lu]\n", (unsigned long) a->pw_gid, (unsigned long) b->pw_gid);
return 1;
}
diff --git a/src/utils/pacat.c b/src/utils/pacat.c
index 79936fd7..749593ea 100644
--- a/src/utils/pacat.c
+++ b/src/utils/pacat.c
@@ -105,6 +105,7 @@ static void context_drain_complete(pa_context*c, void *userdata) {
/* Stream draining complete */
static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
+ pa_operation *o = NULL;
if (!success) {
pa_log(_("Failed to drain stream: %s"), pa_strerror(pa_context_errno(context)));
@@ -118,9 +119,10 @@ static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
pa_stream_unref(stream);
stream = NULL;
- if (!pa_context_drain(context, context_drain_complete, NULL))
+ if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
pa_context_disconnect(context);
else {
+ pa_operation_unref(o);
if (verbose)
pa_log(_("Draining connection to server."));
}
@@ -604,6 +606,7 @@ static void stream_update_timing_callback(pa_stream *s, int success, void *userd
fprintf(stderr, " \r");
}
+#ifdef SIGUSR1
/* Someone requested that the latency is shown */
static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) {
@@ -612,6 +615,7 @@ static void sigusr1_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int s
pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL));
}
+#endif
static void time_event_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c
index 143a948d..4d07c4c2 100644
--- a/src/utils/pacmd.c
+++ b/src/utils/pacmd.c
@@ -44,8 +44,7 @@
#include <pulsecore/pid.h>
int main(int argc, char*argv[]) {
-
- pid_t pid ;
+ pid_t pid;
int fd = -1;
int ret = 1, i;
struct sockaddr_un sa;
diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index 98c4d455..ad5c0b81 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -723,7 +723,7 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
sample_length -= length;
- if (sample_length <= 0) {
+ if (sample_length <= 0) {
pa_stream_set_write_callback(sample_stream, NULL, NULL);
pa_stream_finish_upload(sample_stream);
}
diff --git a/src/utils/padsp.c b/src/utils/padsp.c
index ec0c46d9..ab9d18a3 100644
--- a/src/utils/padsp.c
+++ b/src/utils/padsp.c
@@ -282,7 +282,7 @@ static void debug(int level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3);
#define DEBUG_LEVEL_ALWAYS 0
#define DEBUG_LEVEL_NORMAL 1
-#define DEBUG_LEVEL_VERBOSE 2
+#define DEBUG_LEVEL_VERBOSE 2
static void debug(int level, const char *format, ...) {
va_list ap;
@@ -1596,7 +1596,7 @@ static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno
*(int*) argp =
((v->values[0]*100/PA_VOLUME_NORM)) |
- ((v->values[v->channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM) << 8);
+ ((v->values[v->channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM) << 8);
pa_threaded_mainloop_unlock(i->mainloop);
@@ -2077,7 +2077,7 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno)
case SNDCTL_DSP_GETCAPS:
debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n");
- *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER
+ *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER
#ifdef DSP_CAP_MULTI
| DSP_CAP_MULTI
#endif
diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c
index e155888c..6600363b 100644
--- a/src/utils/pax11publish.c
+++ b/src/utils/pax11publish.c
@@ -33,6 +33,7 @@
#include <pulse/util.h>
#include <pulse/i18n.h>
+#include <pulse/client-conf.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
@@ -40,7 +41,6 @@
#include <pulsecore/native-common.h>
#include <pulsecore/x11prop.h>
-#include "../pulse/client-conf.h"
int main(int argc, char *argv[]) {
const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE;
@@ -209,6 +209,7 @@ int main(int argc, char *argv[]) {
pa_x11_del_prop(xcb, screen, "PULSE_SOURCE");
pa_x11_del_prop(xcb, screen, "PULSE_ID");
pa_x11_del_prop(xcb, screen, "PULSE_COOKIE");
+ pa_x11_del_prop(xcb, screen, "PULSE_SESSION_ID");
break;
default: