summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore22
-rw-r--r--Makefile.am2
-rw-r--r--README35
-rw-r--r--acinclude.m414
-rwxr-xr-xautogen.sh1
-rwxr-xr-xbootstrap.sh3
-rw-r--r--configure.ac12
-rw-r--r--doxygen/.gitignore1
-rw-r--r--doxygen/Makefile.am2
-rw-r--r--man/.gitignore4
-rw-r--r--man/Makefile.am28
-rw-r--r--man/default.pa.5.xml.in2
-rw-r--r--man/esdcompat.1.xml.in2
-rw-r--r--man/pabrowse.1.xml.in2
-rw-r--r--man/pacat.1.xml.in2
-rw-r--r--man/pacmd.1.xml.in2
-rw-r--r--man/pactl.1.xml.in2
-rw-r--r--man/padsp.1.xml.in2
-rw-r--r--man/paplay.1.xml.in2
-rw-r--r--man/pasuspender.1.xml.in2
-rw-r--r--man/pax11publish.1.xml.in2
-rw-r--r--man/pulse-client.conf.5.xml.in2
-rw-r--r--man/pulse-daemon.conf.5.xml.in2
-rw-r--r--man/pulseaudio.1.xml.in13
-rw-r--r--man/xmltoman.css2
-rw-r--r--man/xmltoman.dtd6
-rw-r--r--man/xmltoman.xsl16
-rw-r--r--src/.gitignore56
-rw-r--r--src/Makefile.am53
-rw-r--r--src/daemon/caps.c35
-rw-r--r--src/daemon/caps.h5
-rw-r--r--src/daemon/cmdline.c12
-rw-r--r--src/daemon/cmdline.h2
-rw-r--r--src/daemon/cpulimit.c2
-rw-r--r--src/daemon/cpulimit.h2
-rw-r--r--src/daemon/daemon-conf.c6
-rw-r--r--src/daemon/daemon-conf.h3
-rw-r--r--src/daemon/daemon.conf.in2
-rwxr-xr-xsrc/daemon/default.pa.in14
-rw-r--r--src/daemon/dumpmodules.c2
-rw-r--r--src/daemon/dumpmodules.h2
-rwxr-xr-xsrc/daemon/esdcompat.in2
-rw-r--r--src/daemon/ltdl-bind-now.c2
-rw-r--r--src/daemon/ltdl-bind-now.h2
-rw-r--r--src/daemon/main.c111
-rw-r--r--src/daemon/org.pulseaudio.policy2
-rw-r--r--src/daemon/polkit.c2
-rw-r--r--src/daemon/polkit.h2
-rwxr-xr-xsrc/depmod.py3
-rw-r--r--src/map-file3
-rw-r--r--src/modules/.gitignore1
-rw-r--r--src/modules/alsa-util.c24
-rw-r--r--src/modules/alsa-util.h2
-rw-r--r--src/modules/bt-proximity-helper.c2
-rw-r--r--src/modules/dbus-util.c2
-rw-r--r--src/modules/dbus-util.h2
-rw-r--r--src/modules/gconf/gconf-helper.c2
-rw-r--r--src/modules/gconf/module-gconf.c2
-rw-r--r--src/modules/module-alsa-sink.c16
-rw-r--r--src/modules/module-alsa-source.c12
-rw-r--r--src/modules/module-always-sink.c178
-rw-r--r--src/modules/module-bt-proximity.c2
-rw-r--r--src/modules/module-cli.c2
-rw-r--r--src/modules/module-combine.c564
-rw-r--r--src/modules/module-console-kit.c334
-rw-r--r--src/modules/module-default-device-restore.c8
-rw-r--r--src/modules/module-defs.h.m41
-rw-r--r--src/modules/module-detect.c2
-rw-r--r--src/modules/module-device-restore.c17
-rw-r--r--src/modules/module-esound-compat-spawnfd.c2
-rw-r--r--src/modules/module-esound-sink.c2
-rw-r--r--src/modules/module-hal-detect.c2
-rw-r--r--src/modules/module-jack-sink.c5
-rw-r--r--src/modules/module-jack-source.c5
-rw-r--r--src/modules/module-ladspa-sink.c44
-rw-r--r--src/modules/module-lirc.c2
-rw-r--r--src/modules/module-match.c2
-rw-r--r--src/modules/module-mmkbd-evdev.c2
-rw-r--r--src/modules/module-native-protocol-fd.c2
-rw-r--r--src/modules/module-null-sink.c35
-rw-r--r--src/modules/module-oss.c11
-rw-r--r--src/modules/module-pipe-sink.c2
-rw-r--r--src/modules/module-pipe-source.c2
-rw-r--r--src/modules/module-position-event-sounds.c165
-rw-r--r--src/modules/module-protocol-stub.c4
-rw-r--r--src/modules/module-remap-sink.c55
-rw-r--r--src/modules/module-rescue-streams.c6
-rw-r--r--src/modules/module-sine.c2
-rw-r--r--src/modules/module-solaris.c2
-rw-r--r--src/modules/module-suspend-on-idle.c32
-rw-r--r--src/modules/module-tunnel.c762
-rw-r--r--src/modules/module-volume-restore.c14
-rw-r--r--src/modules/module-waveout.c2
-rw-r--r--src/modules/module-x11-bell.c51
-rw-r--r--src/modules/module-x11-publish.c52
-rw-r--r--src/modules/module-x11-xsmp.c97
-rw-r--r--src/modules/module-zeroconf-discover.c13
-rw-r--r--src/modules/module-zeroconf-publish.c14
-rw-r--r--src/modules/oss-util.c2
-rw-r--r--src/modules/oss-util.h2
-rw-r--r--src/modules/rtp/module-rtp-send.c2
-rw-r--r--src/modules/rtp/rtp.c2
-rw-r--r--src/modules/rtp/rtp.h2
-rw-r--r--src/modules/rtp/sap.c2
-rw-r--r--src/modules/rtp/sap.h2
-rw-r--r--src/modules/rtp/sdp.c2
-rw-r--r--src/modules/rtp/sdp.h2
-rw-r--r--src/pulse/.gitignore1
-rw-r--r--src/pulse/browser.c2
-rw-r--r--src/pulse/browser.h2
-rw-r--r--src/pulse/cdecl.h2
-rw-r--r--src/pulse/channelmap.c30
-rw-r--r--src/pulse/channelmap.h14
-rw-r--r--src/pulse/client-conf-x11.c2
-rw-r--r--src/pulse/client-conf-x11.h2
-rw-r--r--src/pulse/client-conf.c8
-rw-r--r--src/pulse/client-conf.h2
-rw-r--r--src/pulse/client.conf.in4
-rw-r--r--src/pulse/context.c153
-rw-r--r--src/pulse/context.h2
-rw-r--r--src/pulse/def.h2
-rw-r--r--src/pulse/error.c2
-rw-r--r--src/pulse/error.h2
-rw-r--r--src/pulse/gccmacro.h2
-rw-r--r--src/pulse/glib-mainloop.c2
-rw-r--r--src/pulse/glib-mainloop.h2
-rw-r--r--src/pulse/internal.h23
-rw-r--r--src/pulse/introspect.c13
-rw-r--r--src/pulse/introspect.h10
-rw-r--r--src/pulse/mainloop-api.c2
-rw-r--r--src/pulse/mainloop-api.h2
-rw-r--r--src/pulse/mainloop-signal.c2
-rw-r--r--src/pulse/mainloop-signal.h2
-rw-r--r--src/pulse/mainloop.c2
-rw-r--r--src/pulse/mainloop.h2
-rw-r--r--src/pulse/operation.c2
-rw-r--r--src/pulse/operation.h2
-rw-r--r--src/pulse/proplist.c2
-rw-r--r--src/pulse/proplist.h48
-rw-r--r--src/pulse/pulseaudio.h2
-rw-r--r--src/pulse/sample.c2
-rw-r--r--src/pulse/sample.h6
-rw-r--r--src/pulse/scache.c15
-rw-r--r--src/pulse/scache.h2
-rw-r--r--src/pulse/simple.c2
-rw-r--r--src/pulse/simple.h2
-rw-r--r--src/pulse/stream.c41
-rw-r--r--src/pulse/stream.h18
-rw-r--r--src/pulse/subscribe.c2
-rw-r--r--src/pulse/subscribe.h2
-rw-r--r--src/pulse/thread-mainloop.c2
-rw-r--r--src/pulse/thread-mainloop.h2
-rw-r--r--src/pulse/timeval.c4
-rw-r--r--src/pulse/timeval.h14
-rw-r--r--src/pulse/utf8.c2
-rw-r--r--src/pulse/utf8.h2
-rw-r--r--src/pulse/util.c2
-rw-r--r--src/pulse/util.h2
-rw-r--r--src/pulse/version.h.in2
-rw-r--r--src/pulse/volume.c2
-rw-r--r--src/pulse/volume.h8
-rw-r--r--src/pulse/xmalloc.c2
-rw-r--r--src/pulse/xmalloc.h2
-rw-r--r--src/pulsecore/asyncmsgq.c2
-rw-r--r--src/pulsecore/asyncmsgq.h2
-rw-r--r--src/pulsecore/asyncq.c2
-rw-r--r--src/pulsecore/asyncq.h2
-rw-r--r--src/pulsecore/atomic.h15
-rw-r--r--src/pulsecore/authkey-prop.c2
-rw-r--r--src/pulsecore/authkey-prop.h2
-rw-r--r--src/pulsecore/authkey.c2
-rw-r--r--src/pulsecore/authkey.h2
-rw-r--r--src/pulsecore/autoload.c2
-rw-r--r--src/pulsecore/autoload.h2
-rw-r--r--src/pulsecore/avahi-wrap.c2
-rw-r--r--src/pulsecore/avahi-wrap.h2
-rw-r--r--src/pulsecore/cli-command.c2
-rw-r--r--src/pulsecore/cli-command.h2
-rw-r--r--src/pulsecore/cli-text.c24
-rw-r--r--src/pulsecore/cli-text.h2
-rw-r--r--src/pulsecore/cli.c2
-rw-r--r--src/pulsecore/cli.h2
-rw-r--r--src/pulsecore/client.c9
-rw-r--r--src/pulsecore/client.h2
-rw-r--r--src/pulsecore/conf-parser.c2
-rw-r--r--src/pulsecore/conf-parser.h2
-rw-r--r--src/pulsecore/core-error.c2
-rw-r--r--src/pulsecore/core-error.h2
-rw-r--r--src/pulsecore/core-scache.c13
-rw-r--r--src/pulsecore/core-scache.h2
-rw-r--r--src/pulsecore/core-subscribe.c2
-rw-r--r--src/pulsecore/core-subscribe.h2
-rw-r--r--src/pulsecore/core-util.c109
-rw-r--r--src/pulsecore/core-util.h14
-rw-r--r--src/pulsecore/core.c10
-rw-r--r--src/pulsecore/core.h3
-rw-r--r--src/pulsecore/creds.h2
-rw-r--r--src/pulsecore/dllmain.c2
-rw-r--r--src/pulsecore/dynarray.c2
-rw-r--r--src/pulsecore/dynarray.h2
-rw-r--r--src/pulsecore/endianmacros.h2
-rw-r--r--src/pulsecore/envelope.c2
-rw-r--r--src/pulsecore/envelope.h2
-rw-r--r--src/pulsecore/esound.h2
-rw-r--r--src/pulsecore/fdsem.c2
-rw-r--r--src/pulsecore/fdsem.h2
-rw-r--r--src/pulsecore/flist.c2
-rw-r--r--src/pulsecore/flist.h2
-rw-r--r--src/pulsecore/hashmap.c34
-rw-r--r--src/pulsecore/hashmap.h9
-rw-r--r--src/pulsecore/hook-list.c39
-rw-r--r--src/pulsecore/hook-list.h16
-rw-r--r--src/pulsecore/idxset.c2
-rw-r--r--src/pulsecore/idxset.h2
-rw-r--r--src/pulsecore/inet_ntop.c2
-rw-r--r--src/pulsecore/inet_pton.c2
-rw-r--r--src/pulsecore/iochannel.c15
-rw-r--r--src/pulsecore/iochannel.h4
-rw-r--r--src/pulsecore/ioline.c2
-rw-r--r--src/pulsecore/ioline.h2
-rw-r--r--src/pulsecore/ipacl.c2
-rw-r--r--src/pulsecore/ipacl.h2
-rw-r--r--src/pulsecore/llist.h2
-rw-r--r--src/pulsecore/log.c2
-rw-r--r--src/pulsecore/log.h2
-rw-r--r--src/pulsecore/ltdl-helper.c2
-rw-r--r--src/pulsecore/ltdl-helper.h2
-rw-r--r--src/pulsecore/macro.h2
-rw-r--r--src/pulsecore/mcalign.c2
-rw-r--r--src/pulsecore/mcalign.h2
-rw-r--r--src/pulsecore/memblock.c2
-rw-r--r--src/pulsecore/memblock.h2
-rw-r--r--src/pulsecore/memblockq.c15
-rw-r--r--src/pulsecore/memblockq.h4
-rw-r--r--src/pulsecore/memchunk.c18
-rw-r--r--src/pulsecore/memchunk.h2
-rw-r--r--src/pulsecore/modargs.c20
-rw-r--r--src/pulsecore/modargs.h2
-rw-r--r--src/pulsecore/modinfo.c2
-rw-r--r--src/pulsecore/modinfo.h2
-rw-r--r--src/pulsecore/module.c4
-rw-r--r--src/pulsecore/module.h2
-rw-r--r--src/pulsecore/msgobject.c2
-rw-r--r--src/pulsecore/msgobject.h2
-rw-r--r--src/pulsecore/mutex-posix.c2
-rw-r--r--src/pulsecore/mutex-win32.c2
-rw-r--r--src/pulsecore/mutex.h2
-rw-r--r--src/pulsecore/namereg.c2
-rw-r--r--src/pulsecore/namereg.h2
-rw-r--r--src/pulsecore/native-common.h2
-rw-r--r--src/pulsecore/object.c2
-rw-r--r--src/pulsecore/object.h2
-rw-r--r--src/pulsecore/once.c2
-rw-r--r--src/pulsecore/once.h2
-rw-r--r--src/pulsecore/packet.c2
-rw-r--r--src/pulsecore/packet.h2
-rw-r--r--src/pulsecore/parseaddr.c2
-rw-r--r--src/pulsecore/parseaddr.h2
-rw-r--r--src/pulsecore/pdispatch.c2
-rw-r--r--src/pulsecore/pdispatch.h2
-rw-r--r--src/pulsecore/pid.c100
-rw-r--r--src/pulsecore/pid.h8
-rw-r--r--src/pulsecore/pipe.c2
-rw-r--r--src/pulsecore/pipe.h2
-rw-r--r--src/pulsecore/play-memblockq.c3
-rw-r--r--src/pulsecore/play-memblockq.h2
-rw-r--r--src/pulsecore/play-memchunk.c2
-rw-r--r--src/pulsecore/play-memchunk.h2
-rw-r--r--src/pulsecore/poll.c2
-rw-r--r--src/pulsecore/poll.h2
-rw-r--r--src/pulsecore/proplist-util.c118
-rw-r--r--src/pulsecore/proplist-util.h29
-rw-r--r--src/pulsecore/props.c2
-rw-r--r--src/pulsecore/props.h2
-rw-r--r--src/pulsecore/protocol-cli.c2
-rw-r--r--src/pulsecore/protocol-cli.h2
-rw-r--r--src/pulsecore/protocol-esound.c6
-rw-r--r--src/pulsecore/protocol-esound.h2
-rw-r--r--src/pulsecore/protocol-http.c2
-rw-r--r--src/pulsecore/protocol-http.h2
-rw-r--r--src/pulsecore/protocol-native.c127
-rw-r--r--src/pulsecore/protocol-native.h2
-rw-r--r--src/pulsecore/protocol-simple.c4
-rw-r--r--src/pulsecore/protocol-simple.h2
-rw-r--r--src/pulsecore/pstream-util.c2
-rw-r--r--src/pulsecore/pstream-util.h2
-rw-r--r--src/pulsecore/pstream.c2
-rw-r--r--src/pulsecore/pstream.h2
-rw-r--r--src/pulsecore/queue.c2
-rw-r--r--src/pulsecore/queue.h2
-rw-r--r--src/pulsecore/random.c8
-rw-r--r--src/pulsecore/random.h2
-rw-r--r--src/pulsecore/refcnt.h2
-rw-r--r--src/pulsecore/resampler.c16
-rw-r--r--src/pulsecore/resampler.h2
-rw-r--r--src/pulsecore/rtclock.c2
-rw-r--r--src/pulsecore/rtclock.h2
-rw-r--r--src/pulsecore/rtpoll.c5
-rw-r--r--src/pulsecore/rtpoll.h2
-rw-r--r--src/pulsecore/rtsig.c2
-rw-r--r--src/pulsecore/rtsig.h2
-rw-r--r--src/pulsecore/sample-util.c2
-rw-r--r--src/pulsecore/sample-util.h2
-rw-r--r--src/pulsecore/sconv-s16be.c2
-rw-r--r--src/pulsecore/sconv-s16be.h2
-rw-r--r--src/pulsecore/sconv-s16le.c2
-rw-r--r--src/pulsecore/sconv-s16le.h2
-rw-r--r--src/pulsecore/sconv.c2
-rw-r--r--src/pulsecore/sconv.h2
-rw-r--r--src/pulsecore/semaphore-posix.c2
-rw-r--r--src/pulsecore/semaphore-win32.c2
-rw-r--r--src/pulsecore/semaphore.h2
-rw-r--r--src/pulsecore/shm.c2
-rw-r--r--src/pulsecore/shm.h2
-rw-r--r--src/pulsecore/shmasyncq.c2
-rw-r--r--src/pulsecore/shmasyncq.h2
-rw-r--r--src/pulsecore/sink-input.c150
-rw-r--r--src/pulsecore/sink-input.h37
-rw-r--r--src/pulsecore/sink.c383
-rw-r--r--src/pulsecore/sink.h46
-rw-r--r--src/pulsecore/sioman.c2
-rw-r--r--src/pulsecore/sioman.h2
-rw-r--r--src/pulsecore/socket-client.c20
-rw-r--r--src/pulsecore/socket-client.h2
-rw-r--r--src/pulsecore/socket-server.c17
-rw-r--r--src/pulsecore/socket-server.h6
-rw-r--r--src/pulsecore/socket-util.c41
-rw-r--r--src/pulsecore/socket-util.h8
-rw-r--r--src/pulsecore/sound-file-stream.c14
-rw-r--r--src/pulsecore/sound-file-stream.h2
-rw-r--r--src/pulsecore/sound-file.c7
-rw-r--r--src/pulsecore/sound-file.h2
-rw-r--r--src/pulsecore/source-output.c113
-rw-r--r--src/pulsecore/source-output.h35
-rw-r--r--src/pulsecore/source.c304
-rw-r--r--src/pulsecore/source.h63
-rw-r--r--src/pulsecore/speexwrap.h2
-rw-r--r--src/pulsecore/start-child.c2
-rw-r--r--src/pulsecore/start-child.h2
-rw-r--r--src/pulsecore/strbuf.c2
-rw-r--r--src/pulsecore/strbuf.h2
-rw-r--r--src/pulsecore/strlist.c2
-rw-r--r--src/pulsecore/strlist.h2
-rw-r--r--src/pulsecore/tagstruct.c2
-rw-r--r--src/pulsecore/tagstruct.h2
-rw-r--r--src/pulsecore/thread-mq.c2
-rw-r--r--src/pulsecore/thread-mq.h2
-rw-r--r--src/pulsecore/thread-posix.c2
-rw-r--r--src/pulsecore/thread-win32.c2
-rw-r--r--src/pulsecore/thread.h2
-rw-r--r--src/pulsecore/time-smoother.c10
-rw-r--r--src/pulsecore/time-smoother.h4
-rw-r--r--src/pulsecore/tokenizer.c2
-rw-r--r--src/pulsecore/tokenizer.h2
-rw-r--r--src/pulsecore/x11prop.c2
-rw-r--r--src/pulsecore/x11prop.h2
-rw-r--r--src/pulsecore/x11wrap.c43
-rw-r--r--src/pulsecore/x11wrap.h12
-rw-r--r--src/tests/asyncmsgq-test.c2
-rw-r--r--src/tests/asyncq-test.c2
-rw-r--r--src/tests/channelmap-test.c7
-rw-r--r--src/tests/close-test.c20
-rw-r--r--src/tests/cpulimit-test.c2
-rw-r--r--src/tests/envelope-test.c2
-rw-r--r--src/tests/flist-test.c2
-rw-r--r--src/tests/get-binary-name-test.c2
-rw-r--r--src/tests/hook-list-test.c12
-rw-r--r--src/tests/interpol-test.c2
-rw-r--r--src/tests/ipacl-test.c2
-rw-r--r--src/tests/mainloop-test.c2
-rw-r--r--src/tests/mcalign-test.c2
-rw-r--r--src/tests/memblock-test.c2
-rw-r--r--src/tests/memblockq-test.c2
-rw-r--r--src/tests/mix-test.c2
-rw-r--r--src/tests/pacat-simple.c2
-rw-r--r--src/tests/parec-simple.c2
-rw-r--r--src/tests/proplist-test.c2
-rw-r--r--src/tests/queue-test.c2
-rw-r--r--src/tests/remix-test.c2
-rw-r--r--src/tests/resampler-test.c2
-rw-r--r--src/tests/rtpoll-test.c2
-rw-r--r--src/tests/rtstutter.c4
-rw-r--r--src/tests/sig2str-test.c2
-rw-r--r--src/tests/smoother-test.c2
-rw-r--r--src/tests/stripnul.c2
-rw-r--r--src/tests/sync-playback.c2
-rw-r--r--src/tests/thread-mainloop-test.c2
-rw-r--r--src/tests/thread-test.c2
-rw-r--r--src/tests/utf8-test.c2
-rw-r--r--src/tests/voltest.c2
-rw-r--r--src/utils/pabrowse.c2
-rw-r--r--src/utils/pacat.c2
-rw-r--r--src/utils/pacmd.c6
-rw-r--r--src/utils/pactl.c2
-rwxr-xr-xsrc/utils/padsp2
-rw-r--r--src/utils/padsp.c2
-rw-r--r--src/utils/paplay.c2
-rw-r--r--src/utils/pasuspender.c2
-rw-r--r--src/utils/pax11publish.c2
-rw-r--r--todo12
400 files changed, 4059 insertions, 2056 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..cadee1cd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+*.tar.gz
+*.pc
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+compile
+config.guess
+config.h
+config.h.in
+config.log
+config.rpath
+config.status
+config.sub
+configure
+depcomp
+install-sh
+libltdl
+libtool
+ltmain.sh
+missing
+stamp-*
diff --git a/Makefile.am b/Makefile.am
index a41dc6c8..61396575 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,3 @@
-# $Id$
-#
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
diff --git a/README b/README
index 005ddf4a..6ca8d291 100644
--- a/README
+++ b/README
@@ -1 +1,34 @@
-For more information see http://pulseaudio.org/
+PULSEAUDIO SOUND SERVER
+
+WEB SITE:
+ http://pulseaudio.org/
+
+GIT:
+ git://git.0pointer.de/pulseaudio.git
+
+GITWEB:
+ http://git.0pointer.de/?p=pulseaudio.git;a=summary
+
+MAILING LIST:
+ https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss
+
+GIT COMMITS MAILING LIST:
+ https://tango.0pointer.de/mailman/listinfo/pulseaudio-commits
+
+TRAC TICKET CHANGES MAILING LIST:
+ https://tango.0pointer.de/mailman/listinfo/pulseaudio-tickets
+
+IRC:
+ #pulseaudio on irc.freenode.org
+
+CIA:
+ http://cia.navi.cx/stats/project/polypaudio
+
+FRESHMEAT:
+ http://freshmeat.net/projects/pulseaudio/
+
+OHLOH:
+ http://www.ohloh.net/projects/4038
+
+AUTHORS:
+ Several
diff --git a/acinclude.m4 b/acinclude.m4
index 723eb87e..02c05186 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -45,7 +45,7 @@ dnl @category InstalledPackages
dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
dnl @version 2006-05-29
dnl @license GPLWithACException
-dnl
+dnl
dnl Checks for GCC shared/pthread inconsistency based on work by
dnl Marcin Owsiany <marcin@owsiany.pl>
@@ -230,7 +230,7 @@ if test "x$acx_pthread_ok" = xyes; then
# architectures and systems. The problem is that in certain
# configurations, when -shared is specified, GCC "forgets" to
# internally use various flags which are still necessary.
-
+
AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies])
check_inconsistencies=yes
case "${host_cpu}-${host_os}" in
@@ -270,13 +270,13 @@ if test "x$acx_pthread_ok" = xyes; then
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[ok=yes])
-
+
if test "x$ok" = xyes; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
-
+
#
# Linux gcc on some architectures such as mips/mipsel forgets
# about -lpthread
@@ -289,7 +289,7 @@ if test "x$acx_pthread_ok" = xyes; then
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[ok=yes])
-
+
if test "x$ok" = xyes; then
AC_MSG_RESULT([yes])
PTHREAD_LIBS="-lpthread $PTHREAD_LIBS"
@@ -308,7 +308,7 @@ if test "x$acx_pthread_ok" = xyes; then
pthread_attr_init(0); pthread_cleanup_push(0, 0);
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
[ok=yes])
-
+
if test "x$ok" = xyes; then
AC_MSG_RESULT([yes])
PTHREAD_LIBS="-lc_r $PTHREAD_LIBS"
@@ -371,7 +371,7 @@ AC_LANG_PROGRAM(
#include <syslog.h>
int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;],
-[struct request_info *req;
+[struct request_info *req;
return hosts_access (req);]),
[AC_DEFINE(HAVE_LIBWRAP, [], [Have tcpwrap?])
LIBWRAP_LIBS="-lwrap"
diff --git a/autogen.sh b/autogen.sh
index 16c57386..4051a22f 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,5 +1,4 @@
#!/bin/sh
-# $Id$
# This file is part of PulseAudio.
#
diff --git a/bootstrap.sh b/bootstrap.sh
index f23acbfe..ceea55b7 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -1,5 +1,4 @@
#!/bin/bash
-# $Id$
# This file is part of PulseAudio.
#
@@ -17,7 +16,7 @@
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-VERSION=1.9
+VERSION=1.10
run_versioned() {
local P
diff --git a/configure.ac b/configure.ac
index ca7565de..296dc17e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,6 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
-# $Id$
-
# This file is part of PulseAudio.
#
# Copyright 2004-2008 Lennart Poettering
@@ -41,7 +39,7 @@ AC_SUBST(PA_PROTOCOL_VERSION, 13)
# The stable ABI for client applications, for the version info x:y:z
# always will hold y=z
-AC_SUBST(LIBPULSE_VERSION_INFO, [4:1:4])
+AC_SUBST(LIBPULSE_VERSION_INFO, [5:0:5])
# A simplified, synchronous, ABI-stable interface for client
# applications, for the version info x:y:z always will hold y=z
@@ -58,7 +56,7 @@ AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:3:0])
# An internally used, ABI-unstable library that contains the
# PulseAudio core, SONAMEs are bumped on every release, version info
# suffix will always be 0:0
-AC_SUBST(LIBPULSECORE_VERSION_INFO, [5:1:0])
+AC_SUBST(LIBPULSECORE_VERSION_INFO, [6:0:0])
AC_CANONICAL_HOST
@@ -1096,6 +1094,10 @@ fi
#### PulseAudio system runtime dir ####
PA_SYSTEM_RUNTIME_PATH="${localstatedir}/run/pulse"
AC_SUBST(PA_SYSTEM_RUNTIME_PATH)
+PA_SYSTEM_CONFIG_PATH="${localstatedir}/lib/pulse"
+AC_SUBST(PA_SYSTEM_CONFIG_PATH)
+PA_SYSTEM_STATE_PATH="${localstatedir}/lib/pulse"
+AC_SUBST(PA_SYSTEM_STATE_PATH)
###################################
# Output #
@@ -1236,6 +1238,8 @@ echo "
sysconfdir: ${sysconfdir}
localstatedir: ${localstatedir}
System Runtime Path: ${PA_SYSTEM_RUNTIME_PATH}
+ System State Path: ${PA_SYSTEM_STATE_PATH}
+ System Config Path: ${PA_SYSTEM_CONFIG_PATH}
Compiler: ${CC}
CFLAGS: ${CFLAGS}
Have X11: ${ENABLE_X11}
diff --git a/doxygen/.gitignore b/doxygen/.gitignore
new file mode 100644
index 00000000..ca9b4441
--- /dev/null
+++ b/doxygen/.gitignore
@@ -0,0 +1 @@
+doxygen.conf
diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am
index c4f66d83..60b00605 100644
--- a/doxygen/Makefile.am
+++ b/doxygen/Makefile.am
@@ -1,5 +1,3 @@
-# $Id$
-#
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
diff --git a/man/.gitignore b/man/.gitignore
new file mode 100644
index 00000000..c213238d
--- /dev/null
+++ b/man/.gitignore
@@ -0,0 +1,4 @@
+*.1
+*.1.xml
+*.5
+*.5.xml
diff --git a/man/Makefile.am b/man/Makefile.am
index 0a355f95..31ac69ce 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -1,5 +1,3 @@
-# $Id$
-#
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
@@ -125,43 +123,43 @@ CLEANFILES += \
$(man_MANS)
pulseaudio.1: pulseaudio.1.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
esdcompat.1: esdcompat.1.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
pax11publish.1: pax11publish.1.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
paplay.1: paplay.1.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
pacat.1: pacat.1.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
pacmd.1: pacmd.1.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
pactl.1: pactl.1.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
pasuspender.1: pasuspender.1.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
padsp.1: padsp.1.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
pabrowse.1: pabrowse.1.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
pulse-daemon.conf.5: pulse-daemon.conf.5.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
pulse-client.conf.5: pulse-client.conf.5.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
default.pa.5: default.pa.5.xml Makefile
- xmltoman $< > $@
+ xmltoman $< > $@ || rm -f $@
xmllint: $(noinst_DATA)
for f in $(noinst_DATA) ; do \
diff --git a/man/default.pa.5.xml.in b/man/default.pa.5.xml.in
index 0f826db6..4caad7c9 100644
--- a/man/default.pa.5.xml.in
+++ b/man/default.pa.5.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/esdcompat.1.xml.in b/man/esdcompat.1.xml.in
index 864dc5db..61fefa3a 100644
--- a/man/esdcompat.1.xml.in
+++ b/man/esdcompat.1.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/pabrowse.1.xml.in b/man/pabrowse.1.xml.in
index b539fb21..33f071be 100644
--- a/man/pabrowse.1.xml.in
+++ b/man/pabrowse.1.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/pacat.1.xml.in b/man/pacat.1.xml.in
index 748d136d..7b0d72b9 100644
--- a/man/pacat.1.xml.in
+++ b/man/pacat.1.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/pacmd.1.xml.in b/man/pacmd.1.xml.in
index b760ba0e..c20c016e 100644
--- a/man/pacmd.1.xml.in
+++ b/man/pacmd.1.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/pactl.1.xml.in b/man/pactl.1.xml.in
index d30d5f7c..8d5bf1d3 100644
--- a/man/pactl.1.xml.in
+++ b/man/pactl.1.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/padsp.1.xml.in b/man/padsp.1.xml.in
index 610a9602..9bbe3d10 100644
--- a/man/padsp.1.xml.in
+++ b/man/padsp.1.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/paplay.1.xml.in b/man/paplay.1.xml.in
index bab45dc3..843b1728 100644
--- a/man/paplay.1.xml.in
+++ b/man/paplay.1.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/pasuspender.1.xml.in b/man/pasuspender.1.xml.in
index 406dfe60..52deae68 100644
--- a/man/pasuspender.1.xml.in
+++ b/man/pasuspender.1.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/pax11publish.1.xml.in b/man/pax11publish.1.xml.in
index 1e3a1f01..3b40b978 100644
--- a/man/pax11publish.1.xml.in
+++ b/man/pax11publish.1.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/pulse-client.conf.5.xml.in b/man/pulse-client.conf.5.xml.in
index dbf8dc0b..ae8de1f8 100644
--- a/man/pulse-client.conf.5.xml.in
+++ b/man/pulse-client.conf.5.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in
index 2768e24e..50e24559 100644
--- a/man/pulse-daemon.conf.5.xml.in
+++ b/man/pulse-daemon.conf.5.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/man/pulseaudio.1.xml.in b/man/pulseaudio.1.xml.in
index 1f53a60b..9ce66f87 100644
--- a/man/pulseaudio.1.xml.in
+++ b/man/pulseaudio.1.xml.in
@@ -2,8 +2,6 @@
<!DOCTYPE manpage SYSTEM "xmltoman.dtd">
<?xml-stylesheet type="text/xsl" href="xmltoman.xsl" ?>
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
@@ -33,6 +31,7 @@ USA.
<cmd>pulseaudio <opt>--dump-modules</opt></cmd>
<cmd>pulseaudio <opt>--dump-resample-methods</opt></cmd>
<cmd>pulseaudio <opt>--cleanup-shm</opt></cmd>
+ <cmd>pulseaudio <opt>--start</opt></cmd>
<cmd>pulseaudio <opt>--kill</opt></cmd>
<cmd>pulseaudio <opt>--check</opt></cmd>
</synopsis>
@@ -91,6 +90,16 @@ USA.
</option>
<option>
+ <p><opt>--start</opt></p>
+
+ <optdesc><p>Start PulseAudio if it is not running yet. This is
+ different from starting PulseAudio without <opt>--start</opt>
+ which would fail if PA is already running. PulseAudio is
+ guaranteed to be fully initialized when this call
+ returns. Implies <opt>--daemon</opt>.</p></optdesc>
+ </option>
+
+ <option>
<p><opt>-k | --kill</opt></p>
<optdesc><p>Kill an already running PulseAudio daemon of the
diff --git a/man/xmltoman.css b/man/xmltoman.css
index 579a4fdc..113aeeca 100644
--- a/man/xmltoman.css
+++ b/man/xmltoman.css
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/man/xmltoman.dtd b/man/xmltoman.dtd
index 121e62c8..4760638e 100644
--- a/man/xmltoman.dtd
+++ b/man/xmltoman.dtd
@@ -1,6 +1,4 @@
-<!-- $Id$ -->
-
-<!--
+<!--
This file is part of PulseAudio.
PulseAudio is free software; you can redistribute it and/or modify it under
@@ -15,7 +13,7 @@
You should have received a copy of the GNU 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.
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-->
<!ELEMENT manpage (synopsis | description | section | options | seealso)*>
diff --git a/man/xmltoman.xsl b/man/xmltoman.xsl
index 8d4ca212..766ab254 100644
--- a/man/xmltoman.xsl
+++ b/man/xmltoman.xsl
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="iso-8859-15"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
-<!--
+<!--
This file is part of PulseAudio.
PulseAudio is free software; you can redistribute it and/or modify it under
@@ -16,24 +16,22 @@
You should have received a copy of the GNU 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.
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-->
-<!-- $Id$ -->
-
<xsl:output method="xml" version="1.0" encoding="iso-8859-15" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes"/>
<xsl:template match="/manpage">
-
+
<html>
<head>
<title><xsl:value-of select="@name"/>(<xsl:value-of select="@section"/>)</title>
<style type="text/css">
- body { color: black; background-color: white; }
- a:link, a:visited { color: #900000; }
- h1 { text-transform:uppercase; font-size: 18pt; }
- p { margin-left:1cm; margin-right:1cm; }
+ body { color: black; background-color: white; }
+ a:link, a:visited { color: #900000; }
+ h1 { text-transform:uppercase; font-size: 18pt; }
+ p { margin-left:1cm; margin-right:1cm; }
.cmd { font-family:monospace; }
.file { font-family:monospace; }
.arg { text-transform:uppercase; font-family:monospace; font-style: italic; }
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 00000000..f3ed2e2e
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,56 @@
+*.lo
+*.o
+*.la
+.deps
+.libs
+Makefile
+Makefile.in
+asyncmsgq-test
+asyncq-test
+bt-proximity-helper
+channelmap-test
+client.conf
+close-test
+cpulimit-test
+cpulimit-test2
+daemon.conf
+default.pa
+envelope-test
+esdcompat
+flist-test
+gconf-helper
+get-binary-name-test
+hook-list-test
+interpol-test
+ipacl-test
+mainloop-test
+mainloop-test-glib
+mcalign-test
+memblock-test
+memblockq-test
+mix-test
+pabrowse
+pacat
+pacat-simple
+pacmd
+pactl
+paplay
+parec-simple
+pasuspender
+pax11publish
+proplist-test
+pulseaudio
+queue-test
+remix-test
+resampler-test
+rtpoll-test
+rtstutter
+sig2str-test
+smoother-test
+stripnul
+strlist-test
+sync-playback
+thread-mainloop-test
+thread-test
+utf8-test
+voltest
diff --git a/src/Makefile.am b/src/Makefile.am
index 799e7b26..9cce6ed4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,3 @@
-# $Id$
-#
# This file is part of PulseAudio.
#
# Copyright 2004-2006 Lennart Poettering
@@ -55,6 +53,8 @@ AM_CFLAGS += -DPA_DLSEARCHPATH=\"$(modlibexecdir)\"
AM_CFLAGS += -DPA_DEFAULT_CONFIG_DIR=\"$(PA_DEFAULT_CONFIG_DIR)\"
AM_CFLAGS += -DPA_BINARY=\"$(PA_BINARY)\"
AM_CFLAGS += -DPA_SYSTEM_RUNTIME_PATH=\"$(PA_SYSTEM_RUNTIME_PATH)\"
+AM_CFLAGS += -DPA_SYSTEM_CONFIG_PATH=\"$(PA_SYSTEM_CONFIG_PATH)\"
+AM_CFLAGS += -DPA_SYSTEM_STATE_PATH=\"$(PA_SYSTEM_STATE_PATH)\"
AM_CFLAGS += -DAO_REQUIRE_CAS
# This cool debug trap works on i386/gcc only
@@ -231,6 +231,7 @@ noinst_PROGRAMS = \
pacat-simple \
parec-simple \
strlist-test \
+ close-test \
voltest \
memblockq-test \
sync-playback \
@@ -356,6 +357,11 @@ strlist_test_CFLAGS = $(AM_CFLAGS)
strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la libstrlist.la
strlist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+close_test_SOURCES = tests/close-test.c
+close_test_CFLAGS = $(AM_CFLAGS)
+close_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la libstrlist.la
+close_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+
voltest_SOURCES = tests/voltest.c
voltest_CFLAGS = $(AM_CFLAGS)
voltest_LDADD = $(AM_LDADD) libpulse.la
@@ -563,6 +569,7 @@ libpulse_la_SOURCES += \
pulsecore/once.c pulsecore/once.h \
pulsecore/rtclock.c pulsecore/rtclock.h \
pulsecore/time-smoother.c pulsecore/time-smoother.h \
+ pulsecore/proplist-util.c pulsecore/proplist-util.h \
$(PA_THREAD_OBJS)
if OS_IS_WIN32
@@ -630,7 +637,7 @@ bin_SCRIPTS += utils/padsp
endif
-libpulsedsp_la_SOURCES = utils/padsp.c
+libpulsedsp_la_SOURCES = utils/padsp.c pulsecore/core-util.c pulsecore/core-util.h pulsecore/core-error.c pulsecore/core-error.h pulsecore/log.c pulsecore/log.h pulsecore/once.c pulsecore/once.h $(PA_THREAD_OBJS)
libpulsedsp_la_CFLAGS = $(AM_CFLAGS)
libpulsedsp_la_LIBADD = $(AM_LIBADD) libpulse.la
libpulsedsp_la_LDFLAGS = -avoid-version
@@ -790,6 +797,7 @@ libpulsecore_la_SOURCES += \
pulsecore/time-smoother.c pulsecore/time-smoother.h \
pulsecore/start-child.c pulsecore/start-child.h \
pulsecore/envelope.c pulsecore/envelope.h \
+ pulsecore/proplist-util.c pulsecore/proplist-util.h \
$(PA_THREAD_OBJS)
if OS_IS_WIN32
@@ -916,7 +924,7 @@ libpstream_la_LIBADD = $(AM_LIBADD) libpulsecore.la libpacket.la libiochannel.la
libpstream_util_la_SOURCES = pulsecore/pstream-util.c pulsecore/pstream-util.h
libpstream_util_la_LDFLAGS = -avoid-version
-libpstream_util_la_LIBADD = $(AM_LIBADD) libpacket.la libpstream.la libtagstruct.la
+libpstream_util_la_LIBADD = $(AM_LIBADD) libpacket.la libpstream.la libtagstruct.la libpulsecore.la
libpdispatch_la_SOURCES = pulsecore/pdispatch.c pulsecore/pdispatch.h
libpdispatch_la_LDFLAGS = -avoid-version
@@ -1013,6 +1021,7 @@ modlibexec_LTLIBRARIES += \
module-volume-restore.la \
module-device-restore.la \
module-default-device-restore.la \
+ module-always-sink.la \
module-rescue-streams.la \
module-suspend-on-idle.la \
module-http-protocol-tcp.la \
@@ -1025,7 +1034,9 @@ modlibexec_LTLIBRARIES += \
module-ladspa-sink.la \
module-esound-sink.la \
module-tunnel-sink.la \
- module-tunnel-source.la
+ module-tunnel-source.la \
+ module-position-event-sounds.la
+
# See comment at librtp.la above
if !OS_IS_WIN32
@@ -1128,6 +1139,12 @@ modlibexec_LTLIBRARIES += \
module-hal-detect.la
endif
+if HAVE_DBUS
+modlibexec_LTLIBRARIES += \
+ libdbus-util.la \
+ module-console-kit.la
+endif
+
if HAVE_BLUEZ
modlibexec_LTLIBRARIES += \
module-bt-proximity.la
@@ -1184,11 +1201,14 @@ SYMDEF_FILES = \
modules/module-volume-restore-symdef.h \
modules/module-device-restore-symdef.h \
modules/module-default-device-restore-symdef.h \
+ modules/module-always-sink-symdef.h \
modules/module-rescue-streams-symdef.h \
modules/module-suspend-on-idle-symdef.h \
modules/module-hal-detect-symdef.h \
modules/module-bt-proximity-symdef.h \
- modules/gconf/module-gconf-symdef.h
+ modules/gconf/module-gconf-symdef.h \
+ modules/module-position-event-sounds-symdef.h \
+ modules/module-console-kit-symdef.h
EXTRA_DIST += $(SYMDEF_FILES)
BUILT_SOURCES += $(SYMDEF_FILES)
@@ -1343,7 +1363,7 @@ module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EX
module_x11_xsmp_la_SOURCES = modules/module-x11-xsmp.c
module_x11_xsmp_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
module_x11_xsmp_la_LDFLAGS = -module -avoid-version
-module_x11_xsmp_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libpulsecore.la
+module_x11_xsmp_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libpulsecore.la
# OSS
@@ -1423,6 +1443,12 @@ module_volume_restore_la_LDFLAGS = -module -avoid-version
module_volume_restore_la_LIBADD = $(AM_LIBADD) libpulsecore.la
module_volume_restore_la_CFLAGS = $(AM_CFLAGS)
+# Position event sounds in space
+module_position_event_sounds_la_SOURCES = modules/module-position-event-sounds.c
+module_position_event_sounds_la_LDFLAGS = -module -avoid-version
+module_position_event_sounds_la_LIBADD = $(AM_LIBADD) libpulsecore.la
+module_position_event_sounds_CFLAGS = $(AM_CFLAGS)
+
# Device volume restore module
module_device_restore_la_SOURCES = modules/module-device-restore.c
module_device_restore_la_LDFLAGS = -module -avoid-version
@@ -1435,6 +1461,12 @@ module_default_device_restore_la_LDFLAGS = -module -avoid-version
module_default_device_restore_la_LIBADD = $(AM_LIBADD) libpulsecore.la
module_default_device_restore_la_CFLAGS = $(AM_CFLAGS)
+# Always Sink module
+module_always_sink_la_SOURCES = modules/module-always-sink.c
+module_always_sink_la_LDFLAGS = -module -avoid-version
+module_always_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la
+module_always_sink_la_CFLAGS = $(AM_CFLAGS)
+
# Rescue streams module
module_rescue_streams_la_SOURCES = modules/module-rescue-streams.c
module_rescue_streams_la_LDFLAGS = -module -avoid-version
@@ -1470,7 +1502,7 @@ module_jack_source_la_LDFLAGS = -module -avoid-version
module_jack_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS)
module_jack_source_la_CFLAGS = $(AM_CFLAGS) $(JACK_CFLAGS)
-# HAL
+# HAL/D-Bus
libdbus_util_la_SOURCES = modules/dbus-util.c modules/dbus-util.h
libdbus_util_la_LDFLAGS = -avoid-version
libdbus_util_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) libpulsecore.la
@@ -1481,6 +1513,11 @@ module_hal_detect_la_LDFLAGS = -module -avoid-version
module_hal_detect_la_LIBADD = $(AM_LIBADD) $(HAL_LIBS) libpulsecore.la libdbus-util.la
module_hal_detect_la_CFLAGS = $(AM_CFLAGS) $(HAL_CFLAGS)
+module_console_kit_la_SOURCES = modules/module-console-kit.c
+module_console_kit_la_LDFLAGS = -module -avoid-version
+module_console_kit_la_LIBADD = $(AM_LIBADD) $(HAL_LIBS) libpulsecore.la libdbus-util.la
+module_console_kit_la_CFLAGS = $(AM_CFLAGS) $(HAL_CFLAGS)
+
# GConf support
module_gconf_la_SOURCES = modules/gconf/module-gconf.c
module_gconf_la_LDFLAGS = -module -avoid-version
diff --git a/src/daemon/caps.c b/src/daemon/caps.c
index e936d6bb..ae07119c 100644
--- a/src/daemon/caps.c
+++ b/src/daemon/caps.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -93,13 +91,18 @@ void pa_limit_caps(void) {
pa_assert_se(cap_clear(caps) == 0);
pa_assert_se(cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET) == 0);
pa_assert_se(cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET) == 0);
- pa_assert_se(cap_set_proc(caps) == 0);
-
- pa_assert_se(prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == 0);
- pa_log_info("Dropped capabilities successfully.");
+ if (cap_set_proc(caps) < 0)
+ /* Hmm, so we couldn't limit our caps, which probably means we
+ * hadn't any in the first place, so let's just make sure of
+ * that */
+ pa_drop_caps();
+ else
+ pa_log_info("Limited capabilities successfully to CAP_SYS_NICE.");
pa_assert_se(cap_free(caps) == 0);
+
+ pa_assert_se(prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == 0);
}
/* Drop all capabilities, effectively becoming a normal user */
@@ -112,17 +115,33 @@ void pa_drop_caps(void) {
pa_assert_se(cap_clear(caps) == 0);
pa_assert_se(cap_set_proc(caps) == 0);
pa_assert_se(cap_free(caps) == 0);
+
+ pa_assert_se(!pa_have_caps());
+}
+
+pa_bool_t pa_have_caps(void) {
+ cap_t caps;
+ cap_flag_value_t flag = CAP_CLEAR;
+
+ pa_assert_se(caps = cap_get_proc());
+ pa_assert_se(cap_get_flag(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0);
+ pa_assert_se(cap_free(caps) == 0);
+
+ return flag == CAP_SET;
}
#else
/* NOOPs in case capabilities are not available. */
-int pa_limit_caps(void) {
- return 0;
+void pa_limit_caps(void) {
}
void pa_drop_caps(void) {
pa_drop_root();
}
+pa_bool_t pa_have_caps(void) {
+ return FALSE;
+}
+
#endif
diff --git a/src/daemon/caps.h b/src/daemon/caps.h
index 5b21f12e..176aa90e 100644
--- a/src/daemon/caps.h
+++ b/src/daemon/caps.h
@@ -1,8 +1,6 @@
#ifndef foocapshfoo
#define foocapshfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -24,8 +22,11 @@
USA.
***/
+#include <pulsecore/macro.h>
+
void pa_drop_root(void);
void pa_drop_caps(void);
void pa_limit_caps(void);
+pa_bool_t pa_have_caps(void);
#endif
diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c
index 97c75f37..4b2466ce 100644
--- a/src/daemon/cmdline.c
+++ b/src/daemon/cmdline.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -66,7 +64,8 @@ enum {
ARG_DISABLE_SHM,
ARG_DUMP_RESAMPLE_METHODS,
ARG_SYSTEM,
- ARG_CLEANUP_SHM
+ ARG_CLEANUP_SHM,
+ ARG_START
};
/* Tabel for getopt_long() */
@@ -91,6 +90,7 @@ static const struct option long_options[] = {
{"dl-search-path", 1, 0, ARG_DL_SEARCH_PATH},
{"resample-method", 1, 0, ARG_RESAMPLE_METHOD},
{"kill", 0, 0, ARG_KILL},
+ {"start", 0, 0, ARG_START},
{"use-pid-file", 2, 0, ARG_USE_PID_FILE},
{"check", 0, 0, ARG_CHECK},
{"system", 2, 0, ARG_SYSTEM},
@@ -119,6 +119,7 @@ void pa_cmdline_help(const char *argv0) {
" --dump-modules Dump list of available modules\n"
" --dump-resample-methods Dump available resample methods\n"
" --cleanup-shm Cleanup stale shared memory segments\n"
+ " --start Start the daemon if it is not running\n"
" -k --kill Kill a running daemon\n"
" --check Check for a running daemon\n\n"
@@ -207,6 +208,11 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d
conf->cmd = PA_CMD_KILL;
break;
+ case ARG_START:
+ conf->cmd = PA_CMD_START;
+ conf->daemonize = TRUE;
+ break;
+
case ARG_CHECK:
conf->cmd = PA_CMD_CHECK;
break;
diff --git a/src/daemon/cmdline.h b/src/daemon/cmdline.h
index 18418894..fd72a6d3 100644
--- a/src/daemon/cmdline.h
+++ b/src/daemon/cmdline.h
@@ -1,8 +1,6 @@
#ifndef foocmdlinehfoo
#define foocmdlinehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c
index 579b91e3..42a71f7e 100644
--- a/src/daemon/cpulimit.c
+++ b/src/daemon/cpulimit.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/cpulimit.h b/src/daemon/cpulimit.h
index 271109b4..cb9a123d 100644
--- a/src/daemon/cpulimit.h
+++ b/src/daemon/cpulimit.h
@@ -1,8 +1,6 @@
#ifndef foocpulimithfoo
#define foocpulimithfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index f9ad7ec0..9ac40901 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -295,7 +293,7 @@ static int parse_sample_rate(const char *filename, unsigned line, const char *lv
pa_assert(rvalue);
pa_assert(data);
- if (pa_atoi(rvalue, &r) < 0 || r > PA_RATE_MAX || r <= 0) {
+ if (pa_atoi(rvalue, &r) < 0 || r > (int32_t) PA_RATE_MAX || r <= 0) {
pa_log("[%s:%u] Invalid sample rate '%s'.", filename, line, rvalue);
return -1;
}
@@ -313,7 +311,7 @@ static int parse_sample_channels(const char *filename, unsigned line, const char
pa_assert(rvalue);
pa_assert(data);
- if (pa_atoi(rvalue, &n) < 0 || n > PA_CHANNELS_MAX || n <= 0) {
+ if (pa_atoi(rvalue, &n) < 0 || n > (int32_t) PA_CHANNELS_MAX || n <= 0) {
pa_log("[%s:%u] Invalid sample channels '%s'.", filename, line, rvalue);
return -1;
}
diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h
index 03a75661..be2fe1ab 100644
--- a/src/daemon/daemon-conf.h
+++ b/src/daemon/daemon-conf.h
@@ -1,8 +1,6 @@
#ifndef foodaemonconfhfoo
#define foodaemonconfhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -37,6 +35,7 @@
/* The actual command to execute */
typedef enum pa_daemon_conf_cmd {
PA_CMD_DAEMON, /* the default */
+ PA_CMD_START,
PA_CMD_HELP,
PA_CMD_VERSION,
PA_CMD_DUMP_CONF,
diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in
index fd35c0f6..dfabcfb2 100644
--- a/src/daemon/daemon.conf.in
+++ b/src/daemon/daemon.conf.in
@@ -1,5 +1,3 @@
-# $Id$
-#
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
index 064a6cc9..aad9f5d6 100755
--- a/src/daemon/default.pa.in
+++ b/src/daemon/default.pa.in
@@ -74,16 +74,26 @@ load-module module-default-device-restore
### connected to dies, similar for sources
load-module module-rescue-streams
+### Make sure we always have a sink around, even if it is a null sink.
+load-module module-always-sink
+
### Automatically suspend sinks/sources that become idle for too long
load-module module-suspend-on-idle
### Load X11 bell module
-#load-module module-x11-bell sample=x11-bell
+#load-module module-x11-bell sample=bell-windowing-system
### Register ourselves in the X11 session manager
# Deactivated by default, to avoid deadlock when PA is started as esd from gnome-session
# Instead we load this via /etc/xdg/autostart/ and "pactl load-module" now
-# load-module module-x11-xsmp
+#load-module module-x11-xsmp
+
+### If autoexit on idle is enabled we want to make sure we only quit
+### when no local session needs us anymore.
+load-module module-console-kit
+
+### Enable positioned event sounds
+load-module module-position-event-sounds
### Load additional modules from GConf settings. This can be configured with the paprefs tool.
### Please keep in mind that the modules configured by paprefs might conflict with manually
diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c
index 68236c70..cd6866aa 100644
--- a/src/daemon/dumpmodules.c
+++ b/src/daemon/dumpmodules.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/dumpmodules.h b/src/daemon/dumpmodules.h
index ab2ddb64..c49a5eda 100644
--- a/src/daemon/dumpmodules.h
+++ b/src/daemon/dumpmodules.h
@@ -1,8 +1,6 @@
#ifndef foodumpmoduleshfoo
#define foodumpmoduleshfoo
-/* $Id*/
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/esdcompat.in b/src/daemon/esdcompat.in
index 942389d2..66501803 100755
--- a/src/daemon/esdcompat.in
+++ b/src/daemon/esdcompat.in
@@ -1,7 +1,5 @@
#!/bin/sh
-# $Id$
-#
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
diff --git a/src/daemon/ltdl-bind-now.c b/src/daemon/ltdl-bind-now.c
index 6915fe0c..b1770674 100644
--- a/src/daemon/ltdl-bind-now.c
+++ b/src/daemon/ltdl-bind-now.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/ltdl-bind-now.h b/src/daemon/ltdl-bind-now.h
index e19c7bc1..f95d13b4 100644
--- a/src/daemon/ltdl-bind-now.h
+++ b/src/daemon/ltdl-bind-now.h
@@ -1,8 +1,6 @@
#ifndef foopulsecoreltdlbindnowhfoo
#define foopulsecoreltdlbindnowhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 789d104b..14594416 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -96,6 +94,8 @@
#include "ltdl-bind-now.h"
#include "polkit.h"
+#define AUTOSPAWN_LOCK "autospawn.lock"
+
#ifdef HAVE_LIBWRAP
/* Only one instance of these variables */
int allow_severity = LOG_INFO;
@@ -202,6 +202,13 @@ static int change_user(void) {
return -1;
}
+ if (pa_make_secure_dir(PA_SYSTEM_STATE_PATH, 0700, pw->pw_uid, gr->gr_gid) < 0) {
+ pa_log("Failed to create '%s': %s", PA_SYSTEM_STATE_PATH, pa_cstrerror(errno));
+ return -1;
+ }
+
+ /* We don't create the config dir here, because we don't need to write to it */
+
if (initgroups(PA_SYSTEM_USER, gr->gr_gid) != 0) {
pa_log("Failed to change group list: %s", pa_cstrerror(errno));
return -1;
@@ -246,7 +253,8 @@ static int change_user(void) {
/* Relevant for pa_runtime_path() */
pa_set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH);
- pa_set_env("PULSE_CONFIG_PATH", PA_SYSTEM_RUNTIME_PATH);
+ pa_set_env("PULSE_CONFIG_PATH", PA_SYSTEM_CONFIG_PATH);
+ pa_set_env("PULSE_STATE_PATH", PA_SYSTEM_STATE_PATH);
pa_log_info("Successfully dropped root privileges.");
@@ -336,6 +344,8 @@ int main(int argc, char *argv[]) {
pa_time_event *win32_timer;
struct timeval win32_tv;
#endif
+ char *lf = NULL;
+ int autospawn_lock_fd = -1;
#if defined(__linux__) && defined(__OPTIMIZE__)
/*
@@ -364,7 +374,7 @@ int main(int argc, char *argv[]) {
suid_root = FALSE;
#endif
- if (suid_root) {
+ if (!real_root) {
/* Drop all capabilities except CAP_SYS_NICE */
pa_limit_caps();
@@ -416,20 +426,26 @@ int main(int argc, char *argv[]) {
pa_log_set_maximal_level(conf->log_level);
pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL);
- if (suid_root) {
- pa_bool_t allow_realtime, allow_high_priority;
+ pa_log_debug("Started as real root: %s, suid root: %s", pa_yes_no(real_root), pa_yes_no(suid_root));
+
+ if (!real_root && pa_have_caps()) {
+ pa_bool_t allow_high_priority = FALSE, allow_realtime = FALSE;
- /* Ok, we're suid root, so let's better not enable high prio
- * or RT by default */
+ /* Let's better not enable high prio or RT by default */
- allow_high_priority = allow_realtime = FALSE;
+ if (conf->high_priority && !allow_high_priority) {
+ if (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) > 0) {
+ pa_log_info("We're in the group '"PA_REALTIME_GROUP"', allowing high-priority scheduling.");
+ allow_high_priority = TRUE;
+ }
+ }
- if (conf->high_priority || conf->realtime_scheduling)
+ if (conf->realtime_scheduling && !allow_realtime) {
if (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) > 0) {
- pa_log_info("We're in the group '"PA_REALTIME_GROUP"', allowing real-time and high-priority scheduling.");
- allow_realtime = conf->realtime_scheduling;
- allow_high_priority = conf->high_priority;
+ pa_log_info("We're in the group '"PA_REALTIME_GROUP"', allowing real-time scheduling.");
+ allow_realtime = TRUE;
}
+ }
#ifdef HAVE_POLKIT
if (conf->high_priority && !allow_high_priority) {
@@ -455,7 +471,6 @@ int main(int argc, char *argv[]) {
* let's give it up early */
pa_drop_caps();
- suid_root = FALSE;
if (conf->high_priority || conf->realtime_scheduling)
pa_log_notice("Called SUID root and real-time/high-priority scheduling was requested in the configuration. However, we lack the necessary priviliges:\n"
@@ -478,13 +493,13 @@ int main(int argc, char *argv[]) {
if (conf->high_priority && !pa_can_high_priority())
pa_log_warn("High-priority scheduling enabled in configuration but not allowed by policy.");
- if (conf->high_priority && conf->cmd == PA_CMD_DAEMON)
+ if (conf->high_priority && (conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START))
pa_raise_priority(conf->nice_level);
- if (suid_root) {
+ if (pa_have_caps()) {
pa_bool_t drop;
- drop = conf->cmd != PA_CMD_DAEMON || !conf->realtime_scheduling;
+ drop = (conf->cmd != PA_CMD_DAEMON && conf->cmd != PA_CMD_START) || !conf->realtime_scheduling;
#ifdef RLIMIT_RTPRIO
if (!drop) {
@@ -520,6 +535,8 @@ int main(int argc, char *argv[]) {
if (conf->realtime_scheduling && !pa_can_realtime())
pa_log_warn("Real-time scheduling enabled in configuration but not allowed by policy.");
+ pa_log_debug("Can realtime: %s, can high-priority: %s", pa_yes_no(pa_can_realtime()), pa_yes_no(pa_can_high_priority()));
+
LTDL_SET_PRELOADED_SYMBOLS();
pa_ltdl_init();
ltdl_init = TRUE;
@@ -600,7 +617,7 @@ int main(int argc, char *argv[]) {
goto finish;
default:
- pa_assert(conf->cmd == PA_CMD_DAEMON);
+ pa_assert(conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START);
}
if (real_root && !conf->system_instance)
@@ -610,6 +627,15 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ if (conf->cmd == PA_CMD_START) {
+ /* If we shall start PA only when it is not running yet, we
+ * first take the autospawn lock to make things
+ * synchronous. */
+
+ lf = pa_runtime_path(AUTOSPAWN_LOCK);
+ autospawn_lock_fd = pa_lock_lockfile(lf);
+ }
+
if (conf->daemonize) {
pid_t child;
int tty_fd;
@@ -653,6 +679,14 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ if (autospawn_lock_fd >= 0) {
+ /* The lock file is unlocked from the parent, so we need
+ * to close it in the child */
+
+ pa_close(autospawn_lock_fd);
+ autospawn_lock_fd = -1;
+ }
+
pa_assert_se(pa_close(daemon_pipe[0]) == 0);
daemon_pipe[0] = -1;
#endif
@@ -705,13 +739,35 @@ int main(int argc, char *argv[]) {
if (change_user() < 0)
goto finish;
+ pa_set_env("PULSE_SYSTEM", conf->system_instance ? "1" : "0");
+
pa_log_info("This is PulseAudio " PACKAGE_VERSION);
pa_log_info("Page size is %lu bytes", (unsigned long) PA_PAGE_SIZE);
- pa_log_info("Using runtime directory %s.", s = pa_get_runtime_dir());
+ if (!(s = pa_get_runtime_dir()))
+ goto finish;
+ pa_log_info("Using runtime directory %s.", s);
pa_xfree(s);
+ if (!(s = pa_get_state_dir()))
+ pa_log_info("Using state directory %s.", s);
+ pa_xfree(s);
+
+ pa_log_info("Running in system mode: %s", pa_yes_no(pa_in_system_mode()));
if (conf->use_pid_file) {
- if (pa_pid_file_create() < 0) {
+ int z;
+
+ if ((z = pa_pid_file_create("pulseaudio")) != 0) {
+
+ if (conf->cmd == PA_CMD_START && z > 0) {
+ /* If we are already running and with are run in
+ * --start mode, then let's return this as success. */
+
+ pa_log_info("z=%i rock!", z);
+
+ retval = 0;
+ goto finish;
+ }
+
pa_log("pa_pid_file_create() failed.");
goto finish;
}
@@ -740,7 +796,6 @@ int main(int argc, char *argv[]) {
goto finish;
}
- c->is_system_instance = !!conf->system_instance;
c->default_sample_spec = conf->default_sample_spec;
c->default_n_fragments = conf->default_n_fragments;
c->default_fragment_size_msec = conf->default_fragment_size_msec;
@@ -810,11 +865,12 @@ int main(int argc, char *argv[]) {
goto finish;
}
-
#ifdef HAVE_FORK
- if (conf->daemonize) {
+ if (daemon_pipe[1] >= 0) {
int ok = 0;
pa_loop_write(daemon_pipe[1], &ok, sizeof(ok), NULL);
+ pa_close(daemon_pipe[1]);
+ daemon_pipe[1] = -1;
}
#endif
@@ -828,6 +884,12 @@ int main(int argc, char *argv[]) {
finish:
+ if (autospawn_lock_fd >= 0)
+ pa_unlock_lockfile(lf, autospawn_lock_fd);
+
+ if (lf)
+ pa_xfree(lf);
+
#ifdef OS_IS_WIN32
if (win32_timer)
pa_mainloop_get_api(mainloop)->time_free(win32_timer);
@@ -844,6 +906,9 @@ finish:
pa_signal_done();
#ifdef HAVE_FORK
+ if (daemon_pipe[1] >= 0)
+ pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL);
+
pa_close_pipe(daemon_pipe);
#endif
diff --git a/src/daemon/org.pulseaudio.policy b/src/daemon/org.pulseaudio.policy
index 507a2cb1..6cdeec68 100644
--- a/src/daemon/org.pulseaudio.policy
+++ b/src/daemon/org.pulseaudio.policy
@@ -3,8 +3,6 @@
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
-<!-- $Id$ -->
-
<!--
This file is part of PulseAudio.
diff --git a/src/daemon/polkit.c b/src/daemon/polkit.c
index ce7c83e0..256e3199 100644
--- a/src/daemon/polkit.c
+++ b/src/daemon/polkit.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/polkit.h b/src/daemon/polkit.h
index cbcf6a6a..0d65ec52 100644
--- a/src/daemon/polkit.h
+++ b/src/daemon/polkit.h
@@ -1,8 +1,6 @@
#ifndef foopolkithfoo
#define foopolkithfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/depmod.py b/src/depmod.py
index a20bc7c0..6cb3cb21 100755
--- a/src/depmod.py
+++ b/src/depmod.py
@@ -1,6 +1,5 @@
#!/usr/bin/python
-# $Id$
-#
+
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
diff --git a/src/map-file b/src/map-file
index d9189743..8d1c582e 100644
--- a/src/map-file
+++ b/src/map-file
@@ -12,6 +12,7 @@ pa_bytes_to_usec;
pa_channel_map_equal;
pa_channel_map_init;
pa_channel_map_init_auto;
+pa_channel_map_init_extend;
pa_channel_map_init_mono;
pa_channel_map_init_stereo;
pa_channel_map_parse;
@@ -180,6 +181,7 @@ pa_stream_get_device_index;
pa_stream_get_device_name;
pa_stream_get_index;
pa_stream_get_latency;
+pa_stream_get_monitor_stream;
pa_stream_get_sample_spec;
pa_stream_get_state;
pa_stream_get_time;
@@ -197,6 +199,7 @@ pa_stream_ref;
pa_stream_set_buffer_attr;
pa_stream_set_latency_update_callback;
pa_stream_set_moved_callback;
+pa_stream_set_monitor_stream;
pa_stream_set_name;
pa_stream_set_overflow_callback;
pa_stream_set_read_callback;
diff --git a/src/modules/.gitignore b/src/modules/.gitignore
new file mode 100644
index 00000000..2d2d942d
--- /dev/null
+++ b/src/modules/.gitignore
@@ -0,0 +1 @@
+module-*-symdef.h
diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c
index d212abc2..5d52cbc9 100644
--- a/src/modules/alsa-util.c
+++ b/src/modules/alsa-util.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -670,26 +668,8 @@ snd_pcm_t *pa_alsa_open_by_device_string(
*dev = d;
- if (ss->channels != map->channels) {
- if (!pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_ALSA)) {
- unsigned c;
- pa_channel_position_t pos;
-
- pa_log_warn("Device has an unknown channel mapping. This is a limitation of ALSA. Synthesizing channel map.");
-
- for (c = ss->channels; c > 0; c--)
- if (pa_channel_map_init_auto(map, c, PA_CHANNEL_MAP_ALSA))
- break;
-
- pa_assert(c > 0);
-
- pos = PA_CHANNEL_POSITION_AUX0;
- for (; c < map->channels; c ++)
- map->map[c] = pos++;
-
- map->channels = ss->channels;
- }
- }
+ if (ss->channels != map->channels)
+ pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_ALSA);
return pcm_handle;
}
diff --git a/src/modules/alsa-util.h b/src/modules/alsa-util.h
index 442c2645..4de8bcd2 100644
--- a/src/modules/alsa-util.h
+++ b/src/modules/alsa-util.h
@@ -1,8 +1,6 @@
#ifndef fooalsautilhfoo
#define fooalsautilhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/bt-proximity-helper.c b/src/modules/bt-proximity-helper.c
index 5f042c37..3767f01c 100644
--- a/src/modules/bt-proximity-helper.c
+++ b/src/modules/bt-proximity-helper.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/*
* Small SUID helper that allows us to ping a BT device. Borrows
* heavily from bluez-utils' l2ping, which is licensed as GPL2+
diff --git a/src/modules/dbus-util.c b/src/modules/dbus-util.c
index fc1e91ea..905be13f 100644
--- a/src/modules/dbus-util.c
+++ b/src/modules/dbus-util.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/dbus-util.h b/src/modules/dbus-util.h
index 8dca54fe..2b24ac63 100644
--- a/src/modules/dbus-util.h
+++ b/src/modules/dbus-util.h
@@ -1,8 +1,6 @@
#ifndef foodbusutilhfoo
#define foodbusutilhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/gconf/gconf-helper.c b/src/modules/gconf/gconf-helper.c
index abd13287..f5016faf 100644
--- a/src/modules/gconf/gconf-helper.c
+++ b/src/modules/gconf/gconf-helper.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c
index 836157d0..a2a43278 100644
--- a/src/modules/gconf/module-gconf.c
+++ b/src/modules/gconf/module-gconf.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c
index 95a72fdc..6765775a 100644
--- a/src/modules/module-alsa-sink.c
+++ b/src/modules/module-alsa-sink.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -277,7 +275,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec) {
* need to guarantee that clients only have to keep around
* a single hw buffer length. */
- if (pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) > max_sleep_usec/2)
+ if (pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) > process_usec+max_sleep_usec/2)
break;
if (PA_UNLIKELY(n <= u->hwbuf_unused_frames))
@@ -389,7 +387,7 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec) {
* need to guarantee that clients only have to keep around
* a single hw buffer length. */
- if (pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) > max_sleep_usec/2)
+ if (pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) > process_usec+max_sleep_usec/2)
break;
if (PA_UNLIKELY(n <= u->hwbuf_unused_frames))
@@ -602,6 +600,8 @@ static int update_sw_params(struct userdata *u) {
return err;
}
+ pa_sink_set_max_request(u->sink, u->hwbuf_size - u->hwbuf_unused_frames * u->frame_size);
+
return 0;
}
@@ -1318,9 +1318,11 @@ int pa__init(pa_module*m) {
fix_tsched_watermark(u);
u->sink->thread_info.max_rewind = use_tsched ? u->hwbuf_size : 0;
- u->sink->max_latency = pa_bytes_to_usec(u->hwbuf_size, &ss);
- if (!use_tsched)
- u->sink->min_latency = u->sink->max_latency;
+ u->sink->thread_info.max_request = u->hwbuf_size;
+
+ pa_sink_set_latency_range(u->sink,
+ !use_tsched ? pa_bytes_to_usec(u->hwbuf_size, &ss) : (pa_usec_t) -1,
+ pa_bytes_to_usec(u->hwbuf_size, &ss));
pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms",
nfrags, (long unsigned) u->fragment_size,
diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c
index e3090109..1cc467d9 100644
--- a/src/modules/module-alsa-source.c
+++ b/src/modules/module-alsa-source.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -262,7 +260,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec) {
left_to_record = check_left_to_record(u, n);
if (u->use_tsched)
- if (pa_bytes_to_usec(left_to_record, &u->source->sample_spec) > max_sleep_usec/2)
+ if (pa_bytes_to_usec(left_to_record, &u->source->sample_spec) > process_usec+max_sleep_usec/2)
break;
if (PA_UNLIKELY(n <= 0))
@@ -359,7 +357,7 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec) {
left_to_record = check_left_to_record(u, n);
if (u->use_tsched)
- if (pa_bytes_to_usec(left_to_record, &u->source->sample_spec) > max_sleep_usec/2)
+ if (pa_bytes_to_usec(left_to_record, &u->source->sample_spec) > process_usec+max_sleep_usec/2)
break;
if (PA_UNLIKELY(n <= 0))
@@ -1152,9 +1150,9 @@ int pa__init(pa_module*m) {
if (use_tsched)
fix_tsched_watermark(u);
- u->source->max_latency = pa_bytes_to_usec(u->hwbuf_size, &ss);
- if (!use_tsched)
- u->source->min_latency = u->source->max_latency;
+ pa_source_set_latency_range(u->source,
+ !use_tsched ? pa_bytes_to_usec(u->hwbuf_size, &ss) : (pa_usec_t) -1,
+ pa_bytes_to_usec(u->hwbuf_size, &ss));
pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms",
nfrags, (long unsigned) u->fragment_size,
diff --git a/src/modules/module-always-sink.c b/src/modules/module-always-sink.c
new file mode 100644
index 00000000..8b67a36d
--- /dev/null
+++ b/src/modules/module-always-sink.c
@@ -0,0 +1,178 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2008 Colin Guthrie
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pulse/xmalloc.h>
+
+#include <pulsecore/core.h>
+#include <pulsecore/sink-input.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/log.h>
+#include <pulsecore/namereg.h>
+#include <pulsecore/core-util.h>
+
+#include "module-always-sink-symdef.h"
+
+PA_MODULE_AUTHOR("Colin Guthrie");
+PA_MODULE_DESCRIPTION("Always keeps at least one sink loaded even if it's a null one");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(TRUE);
+PA_MODULE_USAGE(
+ "sink_name=<name of sink>");
+
+#define DEFAULT_SINK_NAME "auto_null"
+
+static const char* const valid_modargs[] = {
+ "sink_name",
+ NULL,
+};
+
+struct userdata {
+ pa_hook_slot *put_slot, *unlink_slot;
+ pa_module* null_module;
+ pa_bool_t ignore;
+ char *sink_name;
+};
+
+static void load_null_sink_if_needed(pa_core *c, pa_sink *sink, struct userdata* u) {
+ pa_sink *target;
+ uint32_t idx;
+ char *t;
+
+ pa_assert(c);
+ pa_assert(u);
+ pa_assert(!u->null_module);
+
+ /* Loop through all sinks and check to see if we have *any*
+ * sinks. Ignore the sink passed in (if it's not null) */
+ for (target = pa_idxset_first(c->sinks, &idx); target; target = pa_idxset_next(c->sinks, &idx))
+ if (!sink || target != sink)
+ break;
+
+ if (target)
+ return;
+
+ pa_log_debug("Autoloading null-sink as no other sinks detected.");
+
+ u->ignore = TRUE;
+
+ t = pa_sprintf_malloc("sink_name=%s", u->sink_name);
+ u->null_module = pa_module_load(c, "module-null-sink", t);
+ pa_xfree(t);
+
+ u->ignore = FALSE;
+
+ if (!u->null_module)
+ pa_log_warn("Unable to load module-null-sink");
+}
+
+static pa_hook_result_t put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) {
+ struct userdata *u = userdata;
+
+ pa_assert(c);
+ pa_assert(sink);
+ pa_assert(u);
+
+ /* This is us detecting ourselves on load... just ignore this. */
+ if (u->ignore)
+ return PA_HOOK_OK;
+
+ /* Auto-loaded null-sink not active, so ignoring newly detected sink. */
+ if (!u->null_module)
+ return PA_HOOK_OK;
+
+ /* This is us detecting ourselves on load in a different way... just ignore this too. */
+ if (sink->module == u->null_module)
+ return PA_HOOK_OK;
+
+ pa_log_info("A new sink has been discovered. Unloading null-sink.");
+
+ pa_module_unload_request(u->null_module);
+ u->null_module = NULL;
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t unlink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) {
+ struct userdata *u = userdata;
+
+ pa_assert(c);
+ pa_assert(sink);
+ pa_assert(u);
+
+ /* First check to see if it's our own null-sink that's been removed... */
+ if (u->null_module && sink->module == u->null_module) {
+ pa_log_debug("Autoloaded null-sink removed");
+ u->null_module = NULL;
+ return PA_HOOK_OK;
+ }
+
+ load_null_sink_if_needed(c, sink, u);
+
+ return PA_HOOK_OK;
+}
+
+int pa__init(pa_module*m) {
+ pa_modargs *ma = NULL;
+ struct userdata *u;
+
+ pa_assert(m);
+
+ if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+ pa_log("Failed to parse module arguments");
+ return -1;
+ }
+
+ m->userdata = u = pa_xnew(struct userdata, 1);
+ u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
+ u->put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) put_hook_callback, u);
+ u->unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) unlink_hook_callback, u);
+ u->null_module = NULL;
+ u->ignore = FALSE;
+
+ pa_modargs_free(ma);
+
+ load_null_sink_if_needed(m->core, NULL, u);
+
+ return 0;
+}
+
+void pa__done(pa_module*m) {
+ struct userdata *u;
+
+ pa_assert(m);
+
+ if (!(u = m->userdata))
+ return;
+
+ if (u->put_slot)
+ pa_hook_slot_free(u->put_slot);
+ if (u->unlink_slot)
+ pa_hook_slot_free(u->unlink_slot);
+ if (u->null_module)
+ pa_module_unload_request(u->null_module);
+
+ pa_xfree(u->sink_name);
+ pa_xfree(u);
+}
diff --git a/src/modules/module-bt-proximity.c b/src/modules/module-bt-proximity.c
index 62d530d4..77b95868 100644
--- a/src/modules/module-bt-proximity.c
+++ b/src/modules/module-bt-proximity.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c
index ab311a82..df7783fa 100644
--- a/src/modules/module-cli.c
+++ b/src/modules/module-cli.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c
index fc8be18d..cef7a99a 100644
--- a/src/modules/module-combine.c
+++ b/src/modules/module-combine.c
@@ -1,9 +1,7 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
- Copyright 2004-2006 Lennart Poettering
+ Copyright 2004-2008 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
@@ -47,6 +45,7 @@
#include <pulsecore/rtpoll.h>
#include <pulsecore/rtclock.h>
#include <pulsecore/core-error.h>
+#include <pulsecore/time-smoother.h>
#include "module-combine-symdef.h"
@@ -56,7 +55,6 @@ PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
"sink_name=<name for the sink> "
- "master=<master sink> "
"slaves=<slave sinks> "
"adjust_time=<seconds> "
"resample_method=<method> "
@@ -66,13 +64,15 @@ PA_MODULE_USAGE(
"channel_map=<channel map>");
#define DEFAULT_SINK_NAME "combined"
+
#define MEMBLOCKQ_MAXLENGTH (1024*1024*16)
#define DEFAULT_ADJUST_TIME 10
+#define REQUEST_LATENCY_USEC (PA_USEC_PER_MSEC * 200)
+
static const char* const valid_modargs[] = {
"sink_name",
- "master",
"slaves",
"adjust_time",
"resample_method",
@@ -91,12 +91,15 @@ struct output {
pa_asyncmsgq *inq, /* Message queue from the sink thread to this sink input */
*outq; /* Message queue from this sink input to the sink thread */
- pa_rtpoll_item *inq_rtpoll_item, *outq_rtpoll_item;
+ pa_rtpoll_item *inq_rtpoll_item_read, *inq_rtpoll_item_write;
+ pa_rtpoll_item *outq_rtpoll_item_read, *outq_rtpoll_item_write;
pa_memblockq *memblockq;
pa_usec_t total_latency;
+ pa_atomic_t max_request;
+
PA_LLIST_FIELDS(struct output);
};
@@ -113,29 +116,33 @@ struct userdata {
uint32_t adjust_time;
pa_bool_t automatic;
- size_t block_size;
- pa_hook_slot *sink_new_slot, *sink_unlink_slot, *sink_state_changed_slot;
+ pa_hook_slot *sink_put_slot, *sink_unlink_slot, *sink_state_changed_slot;
pa_resample_method_t resample_method;
struct timeval adjust_timestamp;
- struct output *master;
+ pa_usec_t block_usec;
+
pa_idxset* outputs; /* managed in main context */
struct {
PA_LLIST_HEAD(struct output, active_outputs); /* managed in IO thread context */
pa_atomic_t running; /* we cache that value here, so that every thread can query it cheaply */
- struct timeval timestamp;
+ pa_usec_t timestamp;
pa_bool_t in_null_mode;
+ pa_smoother *smoother;
+ uint64_t counter;
} thread_info;
};
enum {
SINK_MESSAGE_ADD_OUTPUT = PA_SINK_MESSAGE_MAX,
SINK_MESSAGE_REMOVE_OUTPUT,
- SINK_MESSAGE_NEED
+ SINK_MESSAGE_NEED,
+ SINK_MESSAGE_UPDATE_LATENCY,
+ SINK_MESSAGE_UPDATE_MAX_REQUEST
};
enum {
@@ -144,14 +151,13 @@ enum {
static void output_free(struct output *o);
static int output_create_sink_input(struct output *o);
-static void update_master(struct userdata *u, struct output *o);
-static void pick_master(struct userdata *u, struct output *except);
static void adjust_rates(struct userdata *u) {
struct output *o;
- pa_usec_t max_sink_latency = 0, min_total_latency = (pa_usec_t) -1, target_latency;
+ pa_usec_t max_sink_latency = 0, min_total_latency = (pa_usec_t) -1, target_latency, avg_total_latency = 0;
uint32_t base_rate;
uint32_t idx;
+ unsigned n = 0;
pa_assert(u);
pa_sink_assert_ref(u->sink);
@@ -159,9 +165,6 @@ static void adjust_rates(struct userdata *u) {
if (pa_idxset_size(u->outputs) <= 0)
return;
- if (!u->master)
- return;
-
if (!PA_SINK_IS_OPENED(pa_sink_get_state(u->sink)))
return;
@@ -171,23 +174,28 @@ static void adjust_rates(struct userdata *u) {
if (!o->sink_input || !PA_SINK_IS_OPENED(pa_sink_get_state(o->sink)))
continue;
- sink_latency = pa_sink_get_latency(o->sink);
- o->total_latency = sink_latency + pa_sink_input_get_latency(o->sink_input);
+ o->total_latency = pa_sink_input_get_latency(o->sink_input, &sink_latency);
+ o->total_latency += sink_latency;
if (sink_latency > max_sink_latency)
max_sink_latency = sink_latency;
if (min_total_latency == (pa_usec_t) -1 || o->total_latency < min_total_latency)
min_total_latency = o->total_latency;
+
+ avg_total_latency += o->total_latency;
+ n++;
}
if (min_total_latency == (pa_usec_t) -1)
return;
+ avg_total_latency /= n;
+
target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency;
- pa_log_info("[%s] target latency is %0.0f usec.", u->sink->name, (float) target_latency);
- pa_log_info("[%s] master %s latency %0.0f usec.", u->sink->name, u->master->sink->name, (float) u->master->total_latency);
+ pa_log_info("[%s] avg total latency is %0.2f msec.", u->sink->name, (double) avg_total_latency / PA_USEC_PER_MSEC);
+ pa_log_info("[%s] target latency is %0.2f msec.", u->sink->name, (double) target_latency / PA_USEC_PER_MSEC);
base_rate = u->sink->sample_spec.rate;
@@ -210,6 +218,8 @@ static void adjust_rates(struct userdata *u) {
pa_sink_input_set_rate(o->sink_input, r);
}
}
+
+ pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_UPDATE_LATENCY, NULL, (int64_t) avg_total_latency, NULL);
}
static void time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) {
@@ -227,6 +237,36 @@ static void time_callback(pa_mainloop_api*a, pa_time_event* e, const struct time
u->sink->core->mainloop->time_restart(e, &n);
}
+static void process_render_null(struct userdata *u, pa_usec_t now) {
+ size_t ate = 0;
+ pa_assert(u);
+
+ if (u->thread_info.in_null_mode)
+ u->thread_info.timestamp = now;
+
+ while (u->thread_info.timestamp < now + u->block_usec) {
+ pa_memchunk chunk;
+
+ pa_sink_render(u->sink, u->sink->thread_info.max_request, &chunk);
+ pa_memblock_unref(chunk.memblock);
+
+ u->thread_info.counter += chunk.length;
+
+/* pa_log_debug("Ate %lu bytes.", (unsigned long) chunk.length); */
+ u->thread_info.timestamp += pa_bytes_to_usec(chunk.length, &u->sink->sample_spec);
+
+ ate += chunk.length;
+
+ if (ate >= u->sink->thread_info.max_request)
+ break;
+ }
+
+/* pa_log_debug("Ate in sum %lu bytes (of %lu)", (unsigned long) ate, (unsigned long) nbytes); */
+
+ pa_smoother_put(u->thread_info.smoother, now,
+ pa_bytes_to_usec(u->thread_info.counter, &u->sink->sample_spec) - (u->thread_info.timestamp - now));
+}
+
static void thread_func(void *userdata) {
struct userdata *u = userdata;
@@ -240,38 +280,23 @@ static void thread_func(void *userdata) {
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
- pa_rtclock_get(&u->thread_info.timestamp);
+ u->thread_info.timestamp = pa_rtclock_usec();
u->thread_info.in_null_mode = FALSE;
for (;;) {
int ret;
/* If no outputs are connected, render some data and drop it immediately. */
- if (u->sink->thread_info.state == PA_SINK_RUNNING && !u->thread_info.active_outputs) {
- struct timeval now;
-
- /* Just rewind if necessary, since we are in NULL mode, we
- * don't have to pass this on */
- pa_sink_process_rewind(u->sink, u->sink->thread_info.rewind_nbytes);
- u->sink->thread_info.rewind_nbytes = 0;
-
- pa_rtclock_get(&now);
-
- if (!u->thread_info.in_null_mode || pa_timeval_cmp(&u->thread_info.timestamp, &now) <= 0) {
- pa_memchunk chunk;
+ if (PA_SINK_IS_OPENED(u->sink->thread_info.state) && !u->thread_info.active_outputs) {
+ pa_usec_t now;
- pa_sink_render_full(u->sink, u->block_size, &chunk);
- pa_memblock_unref(chunk.memblock);
+ now = pa_rtclock_usec();
- if (!u->thread_info.in_null_mode)
- u->thread_info.timestamp = now;
+ if (!u->thread_info.in_null_mode || u->thread_info.timestamp <= now)
+ process_render_null(u, now);
- pa_timeval_add(&u->thread_info.timestamp, pa_bytes_to_usec(u->block_size, &u->sink->sample_spec));
- }
-
- pa_rtpoll_set_timer_absolute(u->rtpoll, &u->thread_info.timestamp);
+ pa_rtpoll_set_timer_absolute(u->rtpoll, u->thread_info.timestamp);
u->thread_info.in_null_mode = TRUE;
-
} else {
pa_rtpoll_set_timer_disabled(u->rtpoll);
u->thread_info.in_null_mode = FALSE;
@@ -303,7 +328,7 @@ static void render_memblock(struct userdata *u, struct output *o, size_t length)
pa_assert(o);
/* We are run by the sink thread, on behalf of an output (o). The
- * other output is waiting for us, hence it is safe to access its
+ * output is waiting for us, hence it is safe to access its
* mainblockq and asyncmsgq directly. */
/* If we are not running, we cannot produce any data */
@@ -323,6 +348,8 @@ static void render_memblock(struct userdata *u, struct output *o, size_t length)
/* Render data! */
pa_sink_render(u->sink, length, &chunk);
+ u->thread_info.counter += chunk.length;
+
/* OK, let's send this data to the other threads */
for (j = u->thread_info.active_outputs; j; j = j->next)
@@ -379,6 +406,42 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
}
/* Called from I/O thread context */
+static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
+ struct output *o;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert(nbytes > 0);
+ pa_assert_se(o = i->userdata);
+
+ pa_memblockq_rewind(o->memblockq, nbytes);
+}
+
+/* Called from I/O thread context */
+static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
+ struct output *o;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(o = i->userdata);
+
+ pa_memblockq_set_maxrewind(o->memblockq, nbytes);
+}
+
+/* Called from I/O thread context */
+static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
+ struct output *o;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(o = i->userdata);
+
+ if (pa_atomic_load(&o->max_request) == (int) nbytes)
+ return;
+
+ pa_atomic_store(&o->max_request, (int) nbytes);
+
+ pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_UPDATE_MAX_REQUEST, NULL, 0, NULL, NULL);
+}
+
+/* Called from I/O thread context */
static void sink_input_attach_cb(pa_sink_input *i) {
struct output *o;
@@ -386,11 +449,17 @@ static void sink_input_attach_cb(pa_sink_input *i) {
pa_assert_se(o = i->userdata);
/* Set up the queue from the sink thread to us */
- pa_assert(!o->inq_rtpoll_item);
- o->inq_rtpoll_item = pa_rtpoll_item_new_asyncmsgq_read(
+ pa_assert(!o->inq_rtpoll_item_read && !o->outq_rtpoll_item_write);
+
+ o->inq_rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read(
i->sink->rtpoll,
PA_RTPOLL_LATE, /* This one is not that important, since we check for data in _peek() anyway. */
o->inq);
+
+ o->outq_rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write(
+ i->sink->rtpoll,
+ PA_RTPOLL_EARLY,
+ o->outq);
}
/* Called from I/O thread context */
@@ -401,9 +470,13 @@ static void sink_input_detach_cb(pa_sink_input *i) {
pa_assert_se(o = i->userdata);
/* Shut down the queue from the sink thread to us */
- pa_assert(o->inq_rtpoll_item);
- pa_rtpoll_item_free(o->inq_rtpoll_item);
- o->inq_rtpoll_item = NULL;
+ pa_assert(o->inq_rtpoll_item_read && o->outq_rtpoll_item_write);
+
+ pa_rtpoll_item_free(o->inq_rtpoll_item_read);
+ o->inq_rtpoll_item_read = NULL;
+
+ pa_rtpoll_item_free(o->outq_rtpoll_item_write);
+ o->outq_rtpoll_item_write = NULL;
}
/* Called from main context */
@@ -417,6 +490,20 @@ static void sink_input_kill_cb(pa_sink_input *i) {
output_free(o);
}
+/* Called from IO thread context */
+static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t state) {
+ struct userdata *u;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(u = i->userdata);
+
+ /* 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)
+ pa_sink_input_request_rewind(i, 0, FALSE, TRUE);
+}
+
/* Called from thread context */
static int sink_input_process_msg(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
struct output *o = PA_SINK_INPUT(obj)->userdata;
@@ -440,8 +527,7 @@ static int sink_input_process_msg(pa_msgobject *obj, int code, void *data, int64
else
pa_memblockq_flush(o->memblockq);
- break;
-
+ return 0;
}
return pa_sink_input_process_msg(obj, code, data, offset, chunk);
@@ -454,11 +540,10 @@ static void disable_output(struct output *o) {
if (!o->sink_input)
return;
- pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_REMOVE_OUTPUT, o, 0, NULL);
pa_sink_input_unlink(o->sink_input);
+ pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_REMOVE_OUTPUT, o, 0, NULL);
pa_sink_input_unref(o->sink_input);
o->sink_input = NULL;
-
}
/* Called from main context */
@@ -490,8 +575,6 @@ static void suspend(struct userdata *u) {
for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx))
disable_output(o);
- pick_master(u, NULL);
-
pa_log_info("Device suspended...");
}
@@ -511,8 +594,6 @@ static void unsuspend(struct userdata *u) {
enable_output(o);
}
- pick_master(u, NULL);
-
pa_log_info("Resumed successfully...");
}
@@ -549,7 +630,25 @@ static int sink_set_state(pa_sink *sink, pa_sink_state_t state) {
return 0;
}
-/* Called from thread context of the master */
+/* Called from IO context */
+static void update_max_request(struct userdata *u) {
+ size_t max_request = 0;
+ struct output *o;
+
+ for (o = u->thread_info.active_outputs; o; o = o->next) {
+ size_t mr = (size_t) pa_atomic_load(&o->max_request);
+
+ if (mr > max_request)
+ max_request = mr;
+ }
+
+ if (max_request <= 0)
+ max_request = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
+
+ pa_sink_set_max_request(u->sink, max_request);
+}
+
+/* Called from thread context of the io thread */
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
struct userdata *u = PA_SINK(o)->userdata;
@@ -557,41 +656,47 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
case PA_SINK_MESSAGE_SET_STATE:
pa_atomic_store(&u->thread_info.running, PA_PTR_TO_UINT(data) == PA_SINK_RUNNING);
- break;
- case PA_SINK_MESSAGE_GET_LATENCY:
+ if (PA_PTR_TO_UINT(data) == PA_SINK_SUSPENDED)
+ pa_smoother_pause(u->thread_info.smoother, pa_rtclock_usec());
+ else
+ pa_smoother_resume(u->thread_info.smoother, pa_rtclock_usec());
- /* This code will only be called when running in NULL
- * mode, i.e. when no output is attached. See
- * sink_get_latency_cb() below */
+ break;
- if (u->thread_info.in_null_mode) {
- struct timeval now;
+ case PA_SINK_MESSAGE_GET_LATENCY: {
+ pa_usec_t x, y, c, *delay = data;
- if (pa_timeval_cmp(&u->thread_info.timestamp, pa_rtclock_get(&now)) > 0) {
- *((pa_usec_t*) data) = pa_timeval_diff(&u->thread_info.timestamp, &now);
- break;
- }
- }
+ x = pa_rtclock_usec();
+ y = pa_smoother_get(u->thread_info.smoother, x);
- *((pa_usec_t*) data) = 0;
+ c = pa_bytes_to_usec(u->thread_info.counter, &u->sink->sample_spec);
- break;
+ if (y < c)
+ *delay = c - y;
+ else
+ *delay = 0;
+
+ return 0;
+ }
case SINK_MESSAGE_ADD_OUTPUT: {
struct output *op = data;
PA_LLIST_PREPEND(struct output, u->thread_info.active_outputs, op);
- pa_assert(!op->outq_rtpoll_item);
-
- /* Create pa_asyncmsgq to the sink thread */
+ pa_assert(!op->outq_rtpoll_item_read && !op->inq_rtpoll_item_write);
- op->outq_rtpoll_item = pa_rtpoll_item_new_asyncmsgq_read(
+ op->outq_rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read(
u->rtpoll,
PA_RTPOLL_EARLY-1, /* This item is very important */
op->outq);
+ op->inq_rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write(
+ u->rtpoll,
+ PA_RTPOLL_EARLY,
+ op->inq);
+ update_max_request(u);
return 0;
}
@@ -600,56 +705,48 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
PA_LLIST_REMOVE(struct output, u->thread_info.active_outputs, op);
- /* Remove the q that leads from this output to the sink thread */
+ pa_assert(op->outq_rtpoll_item_read && op->inq_rtpoll_item_write);
+
+ pa_rtpoll_item_free(op->outq_rtpoll_item_read);
+ op->outq_rtpoll_item_read = NULL;
- pa_assert(op->outq_rtpoll_item);
- pa_rtpoll_item_free(op->outq_rtpoll_item);
- op->outq_rtpoll_item = NULL;
+ pa_rtpoll_item_free(op->inq_rtpoll_item_write);
+ op->inq_rtpoll_item_write = NULL;
+ update_max_request(u);
return 0;
}
case SINK_MESSAGE_NEED:
- render_memblock(u, data, (size_t) offset);
+ render_memblock(u, (struct output*) data, (size_t) offset);
return 0;
- }
- return pa_sink_process_msg(o, code, data, offset, chunk);
-}
-
-/* Called from main context */
-/* static pa_usec_t sink_get_latency_cb(pa_sink *s) { */
-/* struct userdata *u; */
+ case SINK_MESSAGE_UPDATE_LATENCY: {
+ pa_usec_t x, y, latency = (pa_usec_t) offset;
-/* pa_sink_assert_ref(s); */
-/* pa_assert_se(u = s->userdata); */
+ x = pa_rtclock_usec();
+ y = pa_bytes_to_usec(u->thread_info.counter, &u->sink->sample_spec);
-/* if (u->master) { */
-/* /\* If we have a master sink, we just return the latency of it */
-/* * and add our own buffering on top *\/ */
-
-/* if (!u->master->sink_input) */
-/* return 0; */
-
-/* return */
-/* pa_sink_input_get_latency(u->master->sink_input) + */
-/* pa_sink_get_latency(u->master->sink); */
+ if (y > latency)
+ y -= latency;
+ else
+ y = 0;
-/* } else { */
-/* pa_usec_t usec = 0; */
+ pa_smoother_put(u->thread_info.smoother, x, y);
+ return 0;
+ }
-/* /\* We have no master, hence let's ask our own thread which */
-/* * implements the NULL sink *\/ */
+ case SINK_MESSAGE_UPDATE_MAX_REQUEST:
-/* if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) */
-/* return 0; */
+ update_max_request(u);
+ break;
+ }
-/* return usec; */
-/* } */
-/* } */
+ return pa_sink_process_msg(o, code, data, offset, chunk);
+}
static void update_description(struct userdata *u) {
- int first = 1;
+ pa_bool_t first = TRUE;
char *t;
struct output *o;
uint32_t idx;
@@ -668,7 +765,7 @@ static void update_description(struct userdata *u) {
if (first) {
e = pa_sprintf_malloc("%s %s", t, pa_strnull(pa_proplist_gets(o->sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
- first = 0;
+ first = FALSE;
} else
e = pa_sprintf_malloc("%s, %s", t, pa_strnull(pa_proplist_gets(o->sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
@@ -680,57 +777,19 @@ static void update_description(struct userdata *u) {
pa_xfree(t);
}
-static void update_master(struct userdata *u, struct output *o) {
- pa_assert(u);
-
- if (u->master == o)
- return;
-
- if ((u->master = o))
- pa_log_info("Master sink is now '%s'", o->sink_input->sink->name);
- else
- pa_log_info("No master selected, lacking suitable outputs.");
-}
-
-static void pick_master(struct userdata *u, struct output *except) {
- struct output *o;
- uint32_t idx;
- pa_assert(u);
-
- if (u->master &&
- u->master != except &&
- u->master->sink_input &&
- PA_SINK_IS_OPENED(pa_sink_get_state(u->master->sink))) {
- update_master(u, u->master);
- return;
- }
-
- for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx))
- if (o != except &&
- o->sink_input &&
- PA_SINK_IS_OPENED(pa_sink_get_state(o->sink))) {
- update_master(u, o);
- return;
- }
-
- update_master(u, NULL);
-}
-
static int output_create_sink_input(struct output *o) {
pa_sink_input_new_data data;
- char *t;
pa_assert(o);
if (o->sink_input)
return 0;
- t = pa_sprintf_malloc("Simultaneous output on %s", pa_strnull(pa_proplist_gets(o->sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
-
pa_sink_input_new_data_init(&data);
data.sink = o->sink;
data.driver = __FILE__;
- pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, t);
+ pa_proplist_setf(data.proplist, PA_PROP_MEDIA_NAME, "Simultaneous output on %s", pa_strnull(pa_proplist_gets(o->sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
+ pa_proplist_sets(data.proplist, PA_PROP_MEDIA_ROLE, "filter");
pa_sink_input_new_data_set_sample_spec(&data, &o->userdata->sink->sample_spec);
pa_sink_input_new_data_set_channel_map(&data, &o->userdata->sink->channel_map);
data.module = o->userdata->module;
@@ -740,24 +799,28 @@ static int output_create_sink_input(struct output *o) {
pa_sink_input_new_data_done(&data);
- pa_xfree(t);
-
if (!o->sink_input)
return -1;
o->sink_input->parent.process_msg = sink_input_process_msg;
o->sink_input->pop = sink_input_pop_cb;
+ o->sink_input->process_rewind = sink_input_process_rewind_cb;
+ o->sink_input->state_change = sink_input_state_change_cb;
+ o->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
+ o->sink_input->update_max_request = sink_input_update_max_request_cb;
o->sink_input->attach = sink_input_attach_cb;
o->sink_input->detach = sink_input_detach_cb;
o->sink_input->kill = sink_input_kill_cb;
o->sink_input->userdata = o;
+ pa_sink_input_set_requested_latency(o->sink_input, REQUEST_LATENCY_USEC);
return 0;
}
static struct output *output_new(struct userdata *u, pa_sink *sink) {
struct output *o;
+ pa_sink_state_t state;
pa_assert(u);
pa_assert(sink);
@@ -767,8 +830,8 @@ static struct output *output_new(struct userdata *u, pa_sink *sink) {
o->userdata = u;
o->inq = pa_asyncmsgq_new(0);
o->outq = pa_asyncmsgq_new(0);
- o->inq_rtpoll_item = NULL;
- o->outq_rtpoll_item = NULL;
+ o->inq_rtpoll_item_write = o->inq_rtpoll_item_read = NULL;
+ o->outq_rtpoll_item_write = o->outq_rtpoll_item_read = NULL;
o->sink = sink;
o->sink_input = NULL;
o->memblockq = pa_memblockq_new(
@@ -780,22 +843,30 @@ static struct output *output_new(struct userdata *u, pa_sink *sink) {
0,
0,
NULL);
+ pa_atomic_store(&o->max_request, 0);
+ PA_LLIST_INIT(struct output, o);
pa_assert_se(pa_idxset_put(u->outputs, o, NULL) == 0);
- if (u->sink && PA_SINK_IS_LINKED(pa_sink_get_state(u->sink)))
+ state = pa_sink_get_state(u->sink);
+
+ if (state != PA_SINK_INIT)
pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL);
else {
/* If the sink is not yet started, we need to do the activation ourselves */
PA_LLIST_PREPEND(struct output, u->thread_info.active_outputs, o);
- o->outq_rtpoll_item = pa_rtpoll_item_new_asyncmsgq_read(
+ o->outq_rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read(
u->rtpoll,
PA_RTPOLL_EARLY-1, /* This item is very important */
o->outq);
+ o->inq_rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write(
+ u->rtpoll,
+ PA_RTPOLL_EARLY,
+ o->inq);
}
- if (PA_SINK_IS_OPENED(pa_sink_get_state(u->sink)) || pa_sink_get_state(u->sink) == PA_SINK_INIT) {
+ if (PA_SINK_IS_OPENED(state) || state == PA_SINK_INIT) {
pa_sink_suspend(sink, FALSE);
if (PA_SINK_IS_OPENED(pa_sink_get_state(sink)))
@@ -803,7 +874,6 @@ static struct output *output_new(struct userdata *u, pa_sink *sink) {
goto fail;
}
-
update_description(u);
return o;
@@ -833,7 +903,25 @@ fail:
return NULL;
}
-static pa_hook_result_t sink_new_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) {
+static pa_bool_t is_suitable_sink(struct userdata *u, pa_sink *s) {
+ const char *t;
+
+ pa_sink_assert_ref(s);
+
+ if (!(s->flags & PA_SINK_HARDWARE))
+ return FALSE;
+
+ if (s == u->sink)
+ return FALSE;
+
+ if ((t = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_CLASS)))
+ if (strcmp(t, "sound"))
+ return FALSE;
+
+ return TRUE;
+}
+
+static pa_hook_result_t sink_put_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) {
struct output *o;
pa_core_assert_ref(c);
@@ -841,7 +929,7 @@ static pa_hook_result_t sink_new_hook_cb(pa_core *c, pa_sink *s, struct userdata
pa_assert(u);
pa_assert(u->automatic);
- if (!(s->flags & PA_SINK_HARDWARE) || s == u->sink)
+ if (!is_suitable_sink(u, s))
return PA_HOOK_OK;
pa_log_info("Configuring new sink: %s", s->name);
@@ -854,27 +942,34 @@ static pa_hook_result_t sink_new_hook_cb(pa_core *c, pa_sink *s, struct userdata
if (o->sink_input)
pa_sink_input_put(o->sink_input);
- pick_master(u, NULL);
-
return PA_HOOK_OK;
}
-static pa_hook_result_t sink_unlink_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) {
+static struct output* find_output(struct userdata *u, pa_sink *s) {
struct output *o;
uint32_t idx;
- pa_assert(c);
- pa_sink_assert_ref(s);
pa_assert(u);
+ pa_assert(s);
- if (s == u->sink)
- return PA_HOOK_OK;
+ if (u->sink == s)
+ return NULL;
for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx))
if (o->sink == s)
- break;
+ return o;
- if (!o)
+ return NULL;
+}
+
+static pa_hook_result_t sink_unlink_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) {
+ struct output *o;
+
+ pa_assert(c);
+ pa_sink_assert_ref(s);
+ pa_assert(u);
+
+ if (!(o = find_output(u, s)))
return PA_HOOK_OK;
pa_log_info("Unconfiguring sink: %s", s->name);
@@ -886,30 +981,18 @@ static pa_hook_result_t sink_unlink_hook_cb(pa_core *c, pa_sink *s, struct userd
static pa_hook_result_t sink_state_changed_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) {
struct output *o;
- uint32_t idx;
pa_sink_state_t state;
- if (s == u->sink)
- return PA_HOOK_OK;
-
- for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx))
- if (o->sink == s)
- break;
-
- if (!o)
+ if (!(o = find_output(u, s)))
return PA_HOOK_OK;
state = pa_sink_get_state(s);
- if (PA_SINK_IS_OPENED(state) && PA_SINK_IS_OPENED(pa_sink_get_state(u->sink)) && !o->sink_input) {
+ if (PA_SINK_IS_OPENED(state) && PA_SINK_IS_OPENED(pa_sink_get_state(u->sink)) && !o->sink_input)
enable_output(o);
- pick_master(u, NULL);
- }
- if (state == PA_SINK_SUSPENDED && o->sink_input) {
+ if (state == PA_SINK_SUSPENDED && o->sink_input)
disable_output(o);
- pick_master(u, o);
- }
return PA_HOOK_OK;
}
@@ -917,8 +1000,7 @@ static pa_hook_result_t sink_state_changed_hook_cb(pa_core *c, pa_sink *s, struc
int pa__init(pa_module*m) {
struct userdata *u;
pa_modargs *ma = NULL;
- const char *master_name, *slaves, *rm;
- pa_sink *master_sink = NULL;
+ const char *slaves, *rm;
int resample_method = PA_RESAMPLER_TRIVIAL;
pa_sample_spec ss;
pa_channel_map map;
@@ -940,12 +1022,10 @@ int pa__init(pa_module*m) {
}
}
- u = pa_xnew(struct userdata, 1);
+ m->userdata = u = pa_xnew(struct userdata, 1);
u->core = m->core;
u->module = m;
- m->userdata = u;
u->sink = NULL;
- u->master = NULL;
u->time_event = NULL;
u->adjust_time = DEFAULT_ADJUST_TIME;
u->rtpoll = pa_rtpoll_new();
@@ -954,67 +1034,39 @@ int pa__init(pa_module*m) {
u->resample_method = resample_method;
u->outputs = pa_idxset_new(NULL, NULL);
memset(&u->adjust_timestamp, 0, sizeof(u->adjust_timestamp));
- u->sink_new_slot = u->sink_unlink_slot = u->sink_state_changed_slot = NULL;
+ u->sink_put_slot = u->sink_unlink_slot = u->sink_state_changed_slot = NULL;
PA_LLIST_HEAD_INIT(struct output, u->thread_info.active_outputs);
pa_atomic_store(&u->thread_info.running, FALSE);
u->thread_info.in_null_mode = FALSE;
+ u->thread_info.counter = 0;
+ u->thread_info.smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10);
if (pa_modargs_get_value_u32(ma, "adjust_time", &u->adjust_time) < 0) {
pa_log("Failed to parse adjust_time value");
goto fail;
}
- master_name = pa_modargs_get_value(ma, "master", NULL);
slaves = pa_modargs_get_value(ma, "slaves", NULL);
- if (!master_name != !slaves) {
- pa_log("No master or slave sinks specified");
- goto fail;
- }
+ u->automatic = !slaves;
+ ss = m->core->default_sample_spec;
- if (master_name) {
- if (!(master_sink = pa_namereg_get(m->core, master_name, PA_NAMEREG_SINK, 1))) {
- pa_log("Invalid master sink '%s'", master_name);
- goto fail;
- }
-
- ss = master_sink->sample_spec;
- u->automatic = FALSE;
- } else {
- master_sink = NULL;
- ss = m->core->default_sample_spec;
- u->automatic = TRUE;
- }
-
- if ((pa_modargs_get_sample_spec(ma, &ss) < 0)) {
+ if ((pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0)) {
pa_log("Invalid sample specification.");
goto fail;
}
- if (master_sink && ss.channels == master_sink->sample_spec.channels)
- map = master_sink->channel_map;
- else {
- pa_assert_se(pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_AUX));
- pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_DEFAULT);
- }
-
- if ((pa_modargs_get_channel_map(ma, NULL, &map) < 0)) {
- pa_log("Invalid channel map.");
- goto fail;
- }
-
- if (ss.channels != map.channels) {
- pa_log("Channel map and sample specification don't match.");
- goto fail;
- }
-
pa_sink_new_data_init(&data);
- data.name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
data.namereg_fail = FALSE;
data.driver = __FILE__;
data.module = m;
+ pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
pa_sink_new_data_set_sample_spec(&data, &ss);
pa_sink_new_data_set_channel_map(&data, &map);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Simultaneous Output");
+ pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "filter");
+
+ if (slaves)
+ pa_proplist_sets(data.proplist, "combine.slaves", slaves);
u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY);
pa_sink_new_data_done(&data);
@@ -1025,34 +1077,30 @@ int pa__init(pa_module*m) {
}
u->sink->parent.process_msg = sink_process_msg;
-/* u->sink->get_latency = sink_get_latency_cb; */
u->sink->set_state = sink_set_state;
u->sink->userdata = u;
pa_sink_set_rtpoll(u->sink, u->rtpoll);
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
- u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */
- if (u->block_size <= 0)
- u->block_size = pa_frame_size(&ss);
+ pa_sink_set_latency_range(u->sink, REQUEST_LATENCY_USEC, REQUEST_LATENCY_USEC);
+ u->block_usec = u->sink->thread_info.max_latency;
+
+ u->sink->thread_info.max_request =
+ pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
if (!u->automatic) {
const char*split_state;
char *n = NULL;
pa_assert(slaves);
- /* The master and slaves have been specified manually */
-
- if (!(u->master = output_new(u, master_sink))) {
- pa_log("Failed to create master sink input on sink '%s'.", master_sink->name);
- goto fail;
- }
+ /* The slaves have been specified manually */
split_state = NULL;
while ((n = pa_split(slaves, ",", &split_state))) {
pa_sink *slave_sink;
- if (!(slave_sink = pa_namereg_get(m->core, n, PA_NAMEREG_SINK, 1)) || slave_sink == u->sink) {
+ if (!(slave_sink = pa_namereg_get(m->core, n, PA_NAMEREG_SINK, TRUE)) || slave_sink == u->sink) {
pa_log("Invalid slave sink '%s'", n);
pa_xfree(n);
goto fail;
@@ -1069,17 +1117,16 @@ int pa__init(pa_module*m) {
if (pa_idxset_size(u->outputs) <= 1)
pa_log_warn("No slave sinks specified.");
- u->sink_new_slot = NULL;
+ u->sink_put_slot = NULL;
} else {
pa_sink *s;
- /* We're in automatic mode, we elect one hw sink to the master
- * and attach all other hw sinks as slaves to it */
+ /* We're in automatic mode, we add every sink that matches our needs */
for (s = pa_idxset_first(m->core->sinks, &idx); s; s = pa_idxset_next(m->core->sinks, &idx)) {
- if (!(s->flags & PA_SINK_HARDWARE) || s == u->sink)
+ if (!is_suitable_sink(u, s))
continue;
if (!output_new(u, s)) {
@@ -1088,13 +1135,11 @@ int pa__init(pa_module*m) {
}
}
- u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], (pa_hook_cb_t) sink_new_hook_cb, u);
+ u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_put_hook_cb, u);
}
- u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) sink_unlink_hook_cb, u);
- u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], (pa_hook_cb_t) sink_state_changed_hook_cb, u);
-
- pick_master(u, NULL);
+ u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) sink_unlink_hook_cb, u);
+ u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_state_changed_hook_cb, u);
if (!(u->thread = pa_thread_new(thread_func, u))) {
pa_log("Failed to create thread.");
@@ -1132,19 +1177,21 @@ fail:
static void output_free(struct output *o) {
pa_assert(o);
- pick_master(o->userdata, o);
-
disable_output(o);
pa_assert_se(pa_idxset_remove_by_data(o->userdata->outputs, o, NULL));
update_description(o->userdata);
- if (o->inq_rtpoll_item)
- pa_rtpoll_item_free(o->inq_rtpoll_item);
+ if (o->inq_rtpoll_item_read)
+ pa_rtpoll_item_free(o->inq_rtpoll_item_read);
+ if (o->inq_rtpoll_item_write)
+ pa_rtpoll_item_free(o->inq_rtpoll_item_write);
- if (o->outq_rtpoll_item)
- pa_rtpoll_item_free(o->outq_rtpoll_item);
+ if (o->outq_rtpoll_item_read)
+ pa_rtpoll_item_free(o->outq_rtpoll_item_read);
+ if (o->outq_rtpoll_item_write)
+ pa_rtpoll_item_free(o->outq_rtpoll_item_write);
if (o->inq)
pa_asyncmsgq_unref(o->inq);
@@ -1167,8 +1214,8 @@ void pa__done(pa_module*m) {
if (!(u = m->userdata))
return;
- if (u->sink_new_slot)
- pa_hook_slot_free(u->sink_new_slot);
+ if (u->sink_put_slot)
+ pa_hook_slot_free(u->sink_put_slot);
if (u->sink_unlink_slot)
pa_hook_slot_free(u->sink_unlink_slot);
@@ -1202,5 +1249,8 @@ void pa__done(pa_module*m) {
if (u->time_event)
u->core->mainloop->time_free(u->time_event);
+ if (u->thread_info.smoother)
+ pa_smoother_free(u->thread_info.smoother);
+
pa_xfree(u);
}
diff --git a/src/modules/module-console-kit.c b/src/modules/module-console-kit.c
new file mode 100644
index 00000000..3adee99e
--- /dev/null
+++ b/src/modules/module-console-kit.c
@@ -0,0 +1,334 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2008 Lennart Poettering
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <pulse/xmalloc.h>
+#include <pulse/timeval.h>
+
+#include <pulsecore/core-error.h>
+#include <pulsecore/module.h>
+#include <pulsecore/log.h>
+#include <pulsecore/hashmap.h>
+#include <pulsecore/idxset.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/namereg.h>
+#include <pulsecore/core-scache.h>
+#include <pulsecore/modargs.h>
+
+#include "dbus-util.h"
+#include "module-console-kit-symdef.h"
+
+PA_MODULE_AUTHOR("Lennart Poettering");
+PA_MODULE_DESCRIPTION("Create a client for each ConsoleKit session of this user");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(TRUE);
+
+static const char* const valid_modargs[] = {
+ NULL
+};
+
+struct session {
+ char *id;
+ pa_client *client;
+};
+
+struct userdata {
+ pa_core *core;
+ pa_dbus_connection *connection;
+ pa_hashmap *sessions;
+};
+
+static void add_session(struct userdata *u, const char *id) {
+ DBusError error;
+ DBusMessage *m = NULL, *reply = NULL;
+ int32_t uid;
+ struct session *session;
+ char *t;
+
+ dbus_error_init (&error);
+
+ if (pa_hashmap_get(u->sessions, id)) {
+ pa_log_warn("Duplicate session %s, ignoring.", id);
+ return;
+ }
+
+ if (!(m = dbus_message_new_method_call("org.freedesktop.ConsoleKit", id, "org.freedesktop.ConsoleKit.Session", "GetUnixUser"))) {
+ pa_log("Failed to allocate GetUnixUser() method call.");
+ goto fail;
+ }
+
+ if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->connection), m, -1, &error))) {
+ pa_log("GetUnixUser() call failed: %s: %s", error.name, error.message);
+ goto fail;
+ }
+
+ /* FIXME: Why is this in int32? and not an uint32? */
+ if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INT32, &uid, DBUS_TYPE_INVALID)) {
+ pa_log("Failed to parse GetUnixUser() result: %s: %s", error.name, error.message);
+ goto fail;
+ }
+
+ /* We only care about our own sessions */
+ if ((uid_t) uid != getuid())
+ goto fail;
+
+ session = pa_xnew(struct session, 1);
+ session->id = pa_xstrdup(id);
+
+ t = pa_sprintf_malloc("ConsoleKit Session %s", id);
+ session->client = pa_client_new(u->core, __FILE__, t);
+ pa_xfree(t);
+
+ pa_proplist_sets(session->client->proplist, "console-kit.session", id);
+
+ pa_hashmap_put(u->sessions, session->id, session);
+
+ pa_log_debug("Added new session %s", id);
+
+fail:
+
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+}
+
+static void free_session(struct session *session) {
+ pa_assert(session);
+
+ pa_log_debug("Removing session %s", session->id);
+
+ pa_client_free(session->client);
+ pa_xfree(session->id);
+ pa_xfree(session);
+}
+
+static void remove_session(struct userdata *u, const char *id) {
+ struct session *session;
+
+ if (!(session = pa_hashmap_remove(u->sessions, id)))
+ return;
+
+ free_session(session);
+}
+
+static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) {
+ struct userdata *u = userdata;
+ DBusError error;
+ const char *path;
+
+ pa_assert(bus);
+ pa_assert(message);
+ pa_assert(u);
+
+ dbus_error_init(&error);
+
+ pa_log_debug("dbus: interface=%s, path=%s, member=%s\n",
+ dbus_message_get_interface(message),
+ dbus_message_get_path(message),
+ dbus_message_get_member(message));
+
+ if (dbus_message_is_signal(message, "org.freedesktop.ConsoleKit.Seat", "SessionAdded")) {
+
+ if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) {
+ pa_log_error("Failed to parse SessionAdded message: %s: %s", error.name, error.message);
+ goto finish;
+ }
+
+ add_session(u, path);
+
+ } else if (dbus_message_is_signal(message, "org.freedesktop.ConsoleKit.Seat", "SessionRemoved")) {
+
+ if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) {
+ pa_log_error("Failed to parse SessionRemoved message: %s: %s", error.name, error.message);
+ goto finish;
+ }
+
+ remove_session(u, path);
+ }
+
+finish:
+ dbus_error_free(&error);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static int get_session_list(struct userdata *u) {
+ DBusError error;
+ DBusMessage *m = NULL, *reply = NULL;
+ uint32_t uid;
+ DBusMessageIter iter, sub;
+ int ret = -1;
+
+ pa_assert(u);
+
+ dbus_error_init(&error);
+
+ if (!(m = dbus_message_new_method_call("org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit.Manager", "GetSessionsForUnixUser"))) {
+ pa_log("Failed to allocate GetSessionsForUnixUser() method call.");
+ goto fail;
+ }
+
+ uid = (uint32_t) getuid();
+ if (!(dbus_message_append_args(m, DBUS_TYPE_UINT32, &uid, DBUS_TYPE_INVALID))) {
+ pa_log("Failed to append arguments to GetSessionsForUnixUser() method call.");
+ goto fail;
+ }
+
+ if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->connection), m, -1, &error))) {
+ pa_log("GetSessionsForUnixUser() call failed: %s: %s", error.name, error.message);
+ goto fail;
+ }
+
+ dbus_message_iter_init(reply, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_OBJECT_PATH) {
+ pa_log("Failed to parse GetSessionsForUnixUser() result.");
+ goto fail;
+ }
+
+ dbus_message_iter_recurse(&iter, &sub);
+
+ for (;;) {
+ int at;
+ const char *id;
+
+ if ((at = dbus_message_iter_get_arg_type(&sub)) == DBUS_TYPE_INVALID)
+ break;
+
+ assert(at == DBUS_TYPE_OBJECT_PATH);
+ dbus_message_iter_get_basic(&sub, &id);
+
+ add_session(u, id);
+
+ dbus_message_iter_next(&sub);
+ }
+
+ ret = 0;
+
+fail:
+
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return ret;
+}
+
+int pa__init(pa_module*m) {
+ DBusError error;
+ pa_dbus_connection *connection;
+ struct userdata *u = NULL;
+ pa_modargs *ma;
+
+ pa_assert(m);
+
+ dbus_error_init(&error);
+
+ if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+ pa_log("Failed to parse module arguments");
+ goto fail;
+ }
+
+ if (!(connection = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
+
+ if (connection)
+ pa_dbus_connection_unref(connection);
+
+ pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
+ goto fail;
+ }
+
+ m->userdata = u = pa_xnew(struct userdata, 1);
+ u->core = m->core;
+ u->connection = connection;
+ u->sessions = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+
+ if (!dbus_connection_add_filter(pa_dbus_connection_get(connection), filter_cb, u, NULL)) {
+ pa_log_error("Failed to add filter function");
+ goto fail;
+ }
+
+ dbus_bus_add_match(pa_dbus_connection_get(connection), "type='signal',sender='org.freedesktop.ConsoleKit', interface='org.freedesktop.ConsoleKit.Seat'", &error);
+ if (dbus_error_is_set(&error)) {
+ pa_log_error("Unable to subscribe to ConsoleKit signals: %s: %s", error.name, error.message);
+ goto fail;
+ }
+
+ if (get_session_list(u) < 0)
+ goto fail;
+
+ pa_modargs_free(ma);
+
+ return 0;
+
+fail:
+ if (ma)
+ pa_modargs_free(ma);
+
+ dbus_error_free(&error);
+ pa__done(m);
+
+ return -1;
+}
+
+
+void pa__done(pa_module *m) {
+ struct userdata *u;
+ struct session *session;
+
+ pa_assert(m);
+
+ if (!(u = m->userdata))
+ return;
+
+ if (u->sessions) {
+ while ((session = pa_hashmap_steal_first(u->sessions)))
+ free_session(session);
+
+ pa_hashmap_free(u->sessions, NULL, NULL);
+ }
+
+ if (u->connection)
+ pa_dbus_connection_unref(u->connection);
+
+ pa_xfree(u);
+}
diff --git a/src/modules/module-default-device-restore.c b/src/modules/module-default-device-restore.c
index a7fc3a3f..2168ac71 100644
--- a/src/modules/module-default-device-restore.c
+++ b/src/modules/module-default-device-restore.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -158,15 +156,15 @@ static void subscribe_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t id
int pa__init(pa_module *m) {
struct userdata *u;
- pa_assert(u);
+ pa_assert(m);
u = pa_xnew0(struct userdata, 1);
u->core = m->core;
- if (!(u->sink_filename = pa_runtime_path(DEFAULT_SINK_FILE)))
+ if (!(u->sink_filename = pa_state_path(DEFAULT_SINK_FILE)))
goto fail;
- if (!(u->source_filename = pa_runtime_path(DEFAULT_SOURCE_FILE)))
+ if (!(u->source_filename = pa_state_path(DEFAULT_SOURCE_FILE)))
goto fail;
load(u);
diff --git a/src/modules/module-defs.h.m4 b/src/modules/module-defs.h.m4
index a49e8329..64ce1928 100644
--- a/src/modules/module-defs.h.m4
+++ b/src/modules/module-defs.h.m4
@@ -1,4 +1,3 @@
-dnl $Id$
changecom(`/*', `*/')dnl
define(`module_name', patsubst(patsubst(patsubst(fname, `-symdef.h$'), `^.*/'), `[^0-9a-zA-Z]', `_'))dnl
define(`c_symbol', patsubst(module_name, `[^0-9a-zA-Z]', `_'))dnl
diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c
index ee650dfd..13bcfcd1 100644
--- a/src/modules/module-detect.c
+++ b/src/modules/module-detect.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c
index 0a41b84a..b7a1e1b5 100644
--- a/src/modules/module-device-restore.c
+++ b/src/modules/module-device-restore.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -263,7 +261,7 @@ static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_da
int pa__init(pa_module*m) {
pa_modargs *ma = NULL;
struct userdata *u;
- char *fname, *runtime_dir;
+ char *fname, *fn;
char hn[256];
pa_sink *sink;
pa_source *source;
@@ -282,19 +280,20 @@ int pa__init(pa_module*m) {
u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
- u->sink_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_FIXATE], (pa_hook_cb_t) sink_fixate_hook_callback, u);
- u->source_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], (pa_hook_cb_t) source_fixate_hook_callback, u);
+ u->sink_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) sink_fixate_hook_callback, u);
+ u->source_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) source_fixate_hook_callback, u);
m->userdata = u;
if (!pa_get_host_name(hn, sizeof(hn)))
goto fail;
- if (!(runtime_dir = pa_get_runtime_dir()))
- goto fail;
+ fn = pa_sprintf_malloc("device-volumes.%s.gdbm", hn);
+ fname = pa_state_path(fn);
+ pa_xfree(fn);
- fname = pa_sprintf_malloc("%s/device-volumes.%s.gdbm", runtime_dir, hn);
- pa_xfree(runtime_dir);
+ if (!fname)
+ goto fail;
if (!(u->gdbm_file = gdbm_open(fname, 0, GDBM_WRCREAT, 0600, NULL))) {
pa_log("Failed to open volume database '%s': %s", fname, gdbm_strerror(gdbm_errno));
diff --git a/src/modules/module-esound-compat-spawnfd.c b/src/modules/module-esound-compat-spawnfd.c
index 8321192b..8eb4985b 100644
--- a/src/modules/module-esound-compat-spawnfd.c
+++ b/src/modules/module-esound-compat-spawnfd.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c
index 87b87c3d..e189febd 100644
--- a/src/modules/module-esound-sink.c
+++ b/src/modules/module-esound-sink.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c
index 44b31a59..19430a3d 100644
--- a/src/modules/module-hal-detect.c
+++ b/src/modules/module-hal-detect.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c
index 1ef5d235..c4d47f8e 100644
--- a/src/modules/module-jack-sink.c
+++ b/src/modules/module-jack-sink.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -332,8 +330,7 @@ int pa__init(pa_module*m) {
goto fail;
}
- pa_assert_se(pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_AUX));
- pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA);
+ pa_channel_map_init_extend(&map, channels, PA_CHANNEL_MAP_ALSA);
if (pa_modargs_get_channel_map(ma, NULL, &map) < 0 || map.channels != channels) {
pa_log("Failed to parse channel_map= argument.");
goto fail;
diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c
index fa2ec5eb..03f9d15c 100644
--- a/src/modules/module-jack-source.c
+++ b/src/modules/module-jack-source.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -303,8 +301,7 @@ int pa__init(pa_module*m) {
goto fail;
}
- pa_assert_se(pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_AUX));
- pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA);
+ pa_channel_map_init_extend(&map, channels, PA_CHANNEL_MAP_ALSA);
if (pa_modargs_get_channel_map(ma, NULL, &map) < 0 || map.channels != channels) {
pa_log("failed to parse channel_map= argument.");
goto fail;
diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c
index 245efcb0..3e0babfa 100644
--- a/src/modules/module-ladspa-sink.c
+++ b/src/modules/module-ladspa-sink.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -185,6 +183,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
pa_memblock_unref(nchunk.memblock);
}
+ tchunk.length = PA_MIN(nbytes, tchunk.length);
pa_assert(tchunk.length > 0);
fs = pa_frame_size(&i->sample_spec);
@@ -261,7 +260,7 @@ static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
pa_sink_input_assert_ref(i);
pa_assert_se(u = i->userdata);
- if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state))
+ if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state))
return;
pa_memblockq_set_maxrewind(u->memblockq, nbytes);
@@ -269,13 +268,39 @@ static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
}
/* Called from I/O thread context */
+static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
+ struct userdata *u;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(u = i->userdata);
+
+ if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state))
+ return;
+
+ pa_sink_set_max_request(u->sink, nbytes);
+}
+
+/* Called from I/O thread context */
+static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {
+ struct userdata *u;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(u = i->userdata);
+
+ if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state))
+ return;
+
+ pa_sink_update_latency_range(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
+}
+
+/* Called from I/O thread context */
static void sink_input_detach_cb(pa_sink_input *i) {
struct userdata *u;
pa_sink_input_assert_ref(i);
pa_assert_se(u = i->userdata);
- if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state))
+ if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state))
return;
pa_sink_detach_within_thread(u->sink);
@@ -290,15 +315,14 @@ static void sink_input_attach_cb(pa_sink_input *i) {
pa_sink_input_assert_ref(i);
pa_assert_se(u = i->userdata);
- if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state))
+ if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state))
return;
pa_sink_set_asyncmsgq(u->sink, i->sink->asyncmsgq);
pa_sink_set_rtpoll(u->sink, i->sink->rtpoll);
pa_sink_attach_within_thread(u->sink);
- u->sink->max_latency = u->master->max_latency;
- u->sink->min_latency = u->master->min_latency;
+ pa_sink_update_latency_range(u->sink, u->master->thread_info.min_latency, u->master->thread_info.max_latency);
}
/* Called from main context */
@@ -511,7 +535,7 @@ int pa__init(pa_module*m) {
p = 0;
while ((k = pa_split(cdata, ",", &state)) && p < n_control) {
- float f;
+ double f;
if (*k == 0) {
use_default[p++] = TRUE;
@@ -519,7 +543,7 @@ int pa__init(pa_module*m) {
continue;
}
- if (pa_atof(k, &f) < 0) {
+ if (pa_atod(k, &f) < 0) {
pa_log("Failed to parse control value '%s'", k);
pa_xfree(k);
goto fail;
@@ -707,6 +731,8 @@ int pa__init(pa_module*m) {
u->sink_input->pop = sink_input_pop_cb;
u->sink_input->process_rewind = sink_input_process_rewind_cb;
u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
+ u->sink_input->update_max_request = sink_input_update_max_request_cb;
+ u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb;
u->sink_input->kill = sink_input_kill_cb;
u->sink_input->attach = sink_input_attach_cb;
u->sink_input->detach = sink_input_detach_cb;
diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c
index 24542172..0570a6a1 100644
--- a/src/modules/module-lirc.c
+++ b/src/modules/module-lirc.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-match.c b/src/modules/module-match.c
index d0265455..769a6b59 100644
--- a/src/modules/module-match.c
+++ b/src/modules/module-match.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c
index 03c0e973..4388e49c 100644
--- a/src/modules/module-mmkbd-evdev.c
+++ b/src/modules/module-mmkbd-evdev.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-native-protocol-fd.c b/src/modules/module-native-protocol-fd.c
index 53f41896..1a6f5368 100644
--- a/src/modules/module-native-protocol-fd.c
+++ b/src/modules/module-native-protocol-fd.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c
index aff244fa..604ab158 100644
--- a/src/modules/module-null-sink.c
+++ b/src/modules/module-null-sink.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -59,8 +57,8 @@ PA_MODULE_USAGE(
"format=<sample format> "
"channels=<number of channels> "
"rate=<sample rate> "
- "sink_name=<name of sink>"
- "channel_map=<channel map>"
+ "sink_name=<name of sink> "
+ "channel_map=<channel map> "
"description=<description for the sink>");
#define DEFAULT_SINK_NAME "null"
@@ -157,34 +155,32 @@ static void process_rewind(struct userdata *u, pa_usec_t now) {
}
static void process_render(struct userdata *u, pa_usec_t now) {
- size_t nbytes;
size_t ate = 0;
pa_assert(u);
/* This is the configured latency. Sink inputs connected to us
- might not have a single frame more than this value queued. Hence:
- at maximum read this many bytes from the sink inputs. */
-
- nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
+ might not have a single frame more than the maxrequest value
+ queed. Hence: at maximum read this many bytes from the sink
+ inputs. */
/* Fill the buffer up the the latency size */
while (u->timestamp < now + u->block_usec) {
pa_memchunk chunk;
- pa_sink_render(u->sink, nbytes, &chunk);
+ pa_sink_render(u->sink, u->sink->thread_info.max_request, &chunk);
pa_memblock_unref(chunk.memblock);
- pa_log_debug("Ate %lu bytes.", (unsigned long) chunk.length);
+/* pa_log_debug("Ate %lu bytes.", (unsigned long) chunk.length); */
u->timestamp += pa_bytes_to_usec(chunk.length, &u->sink->sample_spec);
ate += chunk.length;
- if (ate >= nbytes)
+ if (ate >= u->sink->thread_info.max_request)
break;
}
- pa_log_debug("Ate in sum %lu bytes (of %lu)", (unsigned long) ate, (unsigned long) nbytes);
+/* pa_log_debug("Ate in sum %lu bytes (of %lu)", (unsigned long) ate, (unsigned long) nbytes); */
}
static void thread_func(void *userdata) {
@@ -203,7 +199,7 @@ static void thread_func(void *userdata) {
int ret;
/* Render some data and drop it immediately */
- if (u->sink->thread_info.state == PA_SINK_RUNNING) {
+ if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
pa_usec_t now;
now = pa_rtclock_usec();
@@ -256,10 +252,9 @@ int pa__init(pa_module*m) {
goto fail;
}
- u = pa_xnew0(struct userdata, 1);
+ m->userdata = u = pa_xnew0(struct userdata, 1);
u->core = m->core;
u->module = m;
- m->userdata = u;
u->rtpoll = pa_rtpoll_new();
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
@@ -270,6 +265,7 @@ int pa__init(pa_module*m) {
pa_sink_new_data_set_sample_spec(&data, &ss);
pa_sink_new_data_set_channel_map(&data, &map);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "Null Output"));
+ pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");
u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY);
pa_sink_new_data_done(&data);
@@ -286,9 +282,12 @@ int pa__init(pa_module*m) {
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
pa_sink_set_rtpoll(u->sink, u->rtpoll);
- u->block_usec = u->sink->max_latency = MAX_LATENCY_USEC;
+ pa_sink_set_latency_range(u->sink, (pa_usec_t) -1, MAX_LATENCY_USEC);
+ u->block_usec = u->sink->thread_info.max_latency;
- u->sink->thread_info.max_rewind = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
+ u->sink->thread_info.max_rewind =
+ u->sink->thread_info.max_request =
+ pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
if (!(u->thread = pa_thread_new(thread_func, u))) {
pa_log("Failed to create thread.");
diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c
index cf7584db..76b13ecc 100644
--- a/src/modules/module-oss.c
+++ b/src/modules/module-oss.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -510,6 +508,9 @@ static int suspend(struct userdata *u) {
return 0;
}
+static int sink_get_volume(pa_sink *s);
+static int source_get_volume(pa_source *s);
+
static int unsuspend(struct userdata *u) {
int m;
pa_sample_spec ss, *ss_original;
@@ -600,9 +601,9 @@ static int unsuspend(struct userdata *u) {
build_pollfd(u);
if (u->sink)
- pa_sink_get_volume(u->sink);
+ sink_get_volume(u->sink);
if (u->source)
- pa_source_get_volume(u->source);
+ source_get_volume(u->source);
pa_log_info("Resumed successfully...");
@@ -1368,6 +1369,8 @@ int pa__init(pa_module*m) {
pa_sink_set_rtpoll(u->sink, u->rtpoll);
u->sink->refresh_volume = TRUE;
+ u->sink->thread_info.max_request = u->out_hwbuf_size;
+
if (use_mmap)
u->out_mmap_memblocks = pa_xnew0(pa_memblock*, u->out_nfrags);
}
diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c
index cc648928..cd25b890 100644
--- a/src/modules/module-pipe-sink.c
+++ b/src/modules/module-pipe-sink.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c
index 83eb4f8a..b0de34ca 100644
--- a/src/modules/module-pipe-source.c
+++ b/src/modules/module-pipe-source.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-position-event-sounds.c b/src/modules/module-position-event-sounds.c
new file mode 100644
index 00000000..90e693a3
--- /dev/null
+++ b/src/modules/module-position-event-sounds.c
@@ -0,0 +1,165 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2006 Lennart Poettering
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <pulse/xmalloc.h>
+#include <pulse/volume.h>
+#include <pulse/channelmap.h>
+
+#include <pulsecore/core-error.h>
+#include <pulsecore/module.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/log.h>
+#include <pulsecore/sink-input.h>
+
+#include "module-position-event-sounds-symdef.h"
+
+PA_MODULE_AUTHOR("Lennart Poettering");
+PA_MODULE_DESCRIPTION("Position event sounds between L and R depending on the position on screen of the widget triggering them.");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(TRUE);
+
+static const char* const valid_modargs[] = {
+ NULL
+};
+
+struct userdata {
+ pa_core *core;
+ pa_hook_slot *sink_input_fixate_hook_slot;
+};
+
+static pa_bool_t is_left(pa_channel_position_t p) {
+ return
+ p == PA_CHANNEL_POSITION_FRONT_LEFT ||
+ p == PA_CHANNEL_POSITION_REAR_LEFT ||
+ p == PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER ||
+ p == PA_CHANNEL_POSITION_SIDE_LEFT ||
+ p == PA_CHANNEL_POSITION_TOP_FRONT_LEFT ||
+ p == PA_CHANNEL_POSITION_TOP_REAR_LEFT;
+}
+
+static pa_bool_t is_right(pa_channel_position_t p) {
+ return
+ p == PA_CHANNEL_POSITION_FRONT_RIGHT ||
+ p == PA_CHANNEL_POSITION_REAR_RIGHT||
+ p == PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER ||
+ p == PA_CHANNEL_POSITION_SIDE_RIGHT ||
+ p == PA_CHANNEL_POSITION_TOP_FRONT_RIGHT ||
+ p == PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
+}
+
+static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *core, pa_sink_input_new_data *data, struct userdata *u) {
+ const char *hpos;
+ double f;
+ unsigned c;
+ char t[PA_CVOLUME_SNPRINT_MAX];
+
+ pa_assert(data);
+
+ if (!(hpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_HPOS)))
+ return PA_HOOK_OK;
+
+ if (pa_atod(hpos, &f) < 0) {
+ pa_log_warn("Failed to parse "PA_PROP_EVENT_MOUSE_HPOS" property '%s'.", hpos);
+ return PA_HOOK_OK;
+ }
+
+ if (f < 0.0 || f > 1.0) {
+ pa_log_warn("Property "PA_PROP_EVENT_MOUSE_HPOS" out of range %0.2f", f);
+ return PA_HOOK_OK;
+ }
+
+ pa_log_debug("Positioning event sound '%s' at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f);
+
+ if (!data->volume_is_set) {
+ pa_cvolume_reset(&data->volume, data->sample_spec.channels);
+ data->volume_is_set = TRUE;
+ }
+
+ for (c = 0; c < data->sample_spec.channels; c++) {
+
+ if (is_left(data->channel_map.map[c]))
+ data->volume.values[c] =
+ pa_sw_volume_multiply(data->volume.values[c], (pa_volume_t) (PA_VOLUME_NORM * (1.0 - f)));
+
+ if (is_right(data->channel_map.map[c]))
+ data->volume.values[c] =
+ pa_sw_volume_multiply(data->volume.values[c], (pa_volume_t) (PA_VOLUME_NORM * f));
+ }
+
+ pa_log_debug("Final volume %s.", pa_cvolume_snprint(t, sizeof(t), &data->volume));
+
+ return PA_HOOK_OK;
+}
+
+int pa__init(pa_module*m) {
+ pa_modargs *ma = NULL;
+ struct userdata *u;
+
+ pa_assert(m);
+
+ if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+ pa_log("Failed to parse module arguments");
+ goto fail;
+ }
+
+ m->userdata = u = pa_xnew(struct userdata, 1);
+ u->core = m->core;
+ u->sink_input_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_fixate_hook_callback, u);
+
+ pa_modargs_free(ma);
+
+ return 0;
+
+fail:
+ pa__done(m);
+
+ if (ma)
+ pa_modargs_free(ma);
+
+ return -1;
+}
+
+void pa__done(pa_module*m) {
+ struct userdata* u;
+
+ pa_assert(m);
+
+ if (!(u = m->userdata))
+ return;
+
+ if (u->sink_input_fixate_hook_slot)
+ pa_hook_slot_free(u->sink_input_fixate_hook_slot);
+
+ pa_xfree(u);
+}
diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c
index 8bcc19b1..0c9529c3 100644
--- a/src/modules/module-protocol-stub.c
+++ b/src/modules/module-protocol-stub.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -271,7 +269,7 @@ int pa__init(pa_module*m) {
/* This socket doesn't reside in our own runtime dir but in
* /tmp/.esd/, hence we have to create the dir first */
- if (pa_make_secure_parent_dir(u->socket_path, m->core->is_system_instance ? 0755 : 0700, (uid_t)-1, (gid_t)-1) < 0) {
+ if (pa_make_secure_parent_dir(u->socket_path, pa_in_system_mode() ? 0755 : 0700, (uid_t)-1, (gid_t)-1) < 0) {
pa_log("Failed to create socket directory '%s': %s\n", u->socket_path, pa_cstrerror(errno));
goto fail;
}
diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c
index 0b9825e1..c87b1ece 100644
--- a/src/modules/module-remap-sink.c
+++ b/src/modules/module-remap-sink.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -51,7 +49,8 @@ PA_MODULE_USAGE(
"format=<sample format> "
"channels=<number of channels> "
"rate=<sample rate> "
- "channel_map=<channel map>");
+ "channel_map=<channel map> "
+ "remix=<remix channels?>");
struct userdata {
pa_core *core;
@@ -69,6 +68,7 @@ static const char* const valid_modargs[] = {
"format",
"channels",
"channel_map",
+ "remix",
NULL
};
@@ -179,20 +179,46 @@ static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
pa_sink_input_assert_ref(i);
pa_assert_se(u = i->userdata);
- if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state))
+ if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state))
return;
pa_sink_set_max_rewind(u->sink, nbytes);
}
/* Called from I/O thread context */
+static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
+ struct userdata *u;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(u = i->userdata);
+
+ if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state))
+ return;
+
+ pa_sink_set_max_request(u->sink, nbytes);
+}
+
+/* Called from I/O thread context */
+static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {
+ struct userdata *u;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(u = i->userdata);
+
+ if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state))
+ return;
+
+ pa_sink_update_latency_range(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
+}
+
+/* Called from I/O thread context */
static void sink_input_detach_cb(pa_sink_input *i) {
struct userdata *u;
pa_sink_input_assert_ref(i);
pa_assert_se(u = i->userdata);
- if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state))
+ if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state))
return;
pa_sink_detach_within_thread(u->sink);
@@ -207,15 +233,14 @@ static void sink_input_attach_cb(pa_sink_input *i) {
pa_sink_input_assert_ref(i);
pa_assert_se(u = i->userdata);
- if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state))
+ if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state))
return;
pa_sink_set_asyncmsgq(u->sink, i->sink->asyncmsgq);
pa_sink_set_rtpoll(u->sink, i->sink->rtpoll);
pa_sink_attach_within_thread(u->sink);
- u->sink->max_latency = u->master->max_latency;
- u->sink->min_latency = u->master->min_latency;
+ pa_sink_update_latency_range(u->sink, u->master->thread_info.min_latency, u->master->thread_info.max_latency);
}
/* Called from main context */
@@ -261,6 +286,7 @@ int pa__init(pa_module*m) {
pa_sink *master;
pa_sink_input_new_data sink_input_data;
pa_sink_new_data sink_data;
+ pa_bool_t remix = TRUE;
pa_assert(m);
@@ -283,7 +309,7 @@ int pa__init(pa_module*m) {
stream_map = sink_map;
if (pa_modargs_get_channel_map(ma, "master_channel_map", &stream_map) < 0) {
- pa_log("Invalid master hannel map");
+ pa_log("Invalid master channel map");
goto fail;
}
@@ -295,6 +321,11 @@ int pa__init(pa_module*m) {
if (pa_channel_map_equal(&stream_map, &master->channel_map))
pa_log_warn("No remapping configured, proceeding nonetheless!");
+ if (pa_modargs_get_value_boolean(ma, "remix", &remix) < 0) {
+ pa_log("Invalid boolean remix parameter");
+ goto fail;
+ }
+
u = pa_xnew0(struct userdata, 1);
u->core = m->core;
u->module = m;
@@ -343,7 +374,7 @@ int pa__init(pa_module*m) {
pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
pa_sink_input_new_data_set_channel_map(&sink_input_data, &stream_map);
- u->sink_input = pa_sink_input_new(m->core, &sink_input_data, PA_SINK_INPUT_DONT_MOVE);
+ u->sink_input = pa_sink_input_new(m->core, &sink_input_data, PA_SINK_INPUT_DONT_MOVE | (remix ? 0 : PA_SINK_INPUT_NO_REMIX));
pa_sink_input_new_data_done(&sink_input_data);
if (!u->sink_input)
@@ -352,9 +383,11 @@ int pa__init(pa_module*m) {
u->sink_input->pop = sink_input_pop_cb;
u->sink_input->process_rewind = sink_input_process_rewind_cb;
u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
- u->sink_input->kill = sink_input_kill_cb;
+ u->sink_input->update_max_request = sink_input_update_max_request_cb;
+ u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb;
u->sink_input->attach = sink_input_attach_cb;
u->sink_input->detach = sink_input_detach_cb;
+ u->sink_input->kill = sink_input_kill_cb;
u->sink_input->state_change = sink_input_state_change_cb;
u->sink_input->userdata = u;
diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c
index 7241a99f..cc6717cb 100644
--- a/src/modules/module-rescue-streams.c
+++ b/src/modules/module-rescue-streams.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -139,8 +137,8 @@ int pa__init(pa_module*m) {
}
m->userdata = u = pa_xnew(struct userdata, 1);
- u->sink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) sink_hook_callback, NULL);
- u->source_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], (pa_hook_cb_t) source_hook_callback, NULL);
+ u->sink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_hook_callback, NULL);
+ u->source_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) source_hook_callback, NULL);
pa_modargs_free(ma);
return 0;
diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c
index 3d917054..38780f24 100644
--- a/src/modules/module-sine.c
+++ b/src/modules/module-sine.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c
index 4a5c88e4..6f50543a 100644
--- a/src/modules/module-solaris.c
+++ b/src/modules/module-solaris.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c
index a3985974..bc7c023c 100644
--- a/src/modules/module-suspend-on-idle.c
+++ b/src/modules/module-suspend-on-idle.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -367,21 +365,21 @@ int pa__init(pa_module*m) {
for (source = pa_idxset_first(m->core->sources, &idx); source; source = pa_idxset_next(m->core->sources, &idx))
device_new_hook_cb(m->core, PA_OBJECT(source), u);
- u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], (pa_hook_cb_t) device_new_hook_cb, u);
- u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], (pa_hook_cb_t) device_new_hook_cb, u);
- u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], (pa_hook_cb_t) device_unlink_hook_cb, u);
- u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], (pa_hook_cb_t) device_unlink_hook_cb, u);
- u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], (pa_hook_cb_t) device_state_changed_hook_cb, u);
- u->source_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], (pa_hook_cb_t) device_state_changed_hook_cb, u);
-
- u->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], (pa_hook_cb_t) sink_input_fixate_hook_cb, u);
- u->source_output_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], (pa_hook_cb_t) source_output_fixate_hook_cb, u);
- u->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], (pa_hook_cb_t) sink_input_unlink_hook_cb, u);
- u->source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], (pa_hook_cb_t) source_output_unlink_hook_cb, u);
- u->sink_input_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], (pa_hook_cb_t) sink_input_move_hook_cb, u);
- u->source_output_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], (pa_hook_cb_t) source_output_move_hook_cb, u);
- u->sink_input_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], (pa_hook_cb_t) sink_input_state_changed_hook_cb, u);
- u->source_output_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], (pa_hook_cb_t) source_output_state_changed_hook_cb, u);
+ u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) device_new_hook_cb, u);
+ u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) device_new_hook_cb, u);
+ u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], PA_HOOK_NORMAL, (pa_hook_cb_t) device_unlink_hook_cb, u);
+ u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], PA_HOOK_NORMAL, (pa_hook_cb_t) device_unlink_hook_cb, u);
+ u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) device_state_changed_hook_cb, u);
+ u->source_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) device_state_changed_hook_cb, u);
+
+ u->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_input_fixate_hook_cb, u);
+ u->source_output_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], PA_HOOK_NORMAL, (pa_hook_cb_t) source_output_fixate_hook_cb, u);
+ u->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_input_unlink_hook_cb, u);
+ u->source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], PA_HOOK_NORMAL, (pa_hook_cb_t) source_output_unlink_hook_cb, u);
+ u->sink_input_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_input_move_hook_cb, u);
+ u->source_output_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], PA_HOOK_NORMAL, (pa_hook_cb_t) source_output_move_hook_cb, u);
+ u->sink_input_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_input_state_changed_hook_cb, u);
+ u->source_output_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) source_output_state_changed_hook_cb, u);
pa_modargs_free(ma);
return 0;
diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c
index 7a87fd8c..86f30817 100644
--- a/src/modules/module-tunnel.c
+++ b/src/modules/module-tunnel.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -56,11 +54,16 @@
#include <pulsecore/thread-mq.h>
#include <pulsecore/rtclock.h>
#include <pulsecore/core-error.h>
+#include <pulsecore/proplist-util.h>
#ifdef TUNNEL_SINK
#include "module-tunnel-sink-symdef.h"
+#else
+#include "module-tunnel-source-symdef.h"
+#endif
+
+#ifdef TUNNEL_SINK
PA_MODULE_DESCRIPTION("Tunnel module for sinks");
-PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
"server=<address> "
"sink=<remote sink name> "
@@ -71,7 +74,6 @@ PA_MODULE_USAGE(
"sink_name=<name for the local sink> "
"channel_map=<channel map>");
#else
-#include "module-tunnel-source-symdef.h"
PA_MODULE_DESCRIPTION("Tunnel module for sources");
PA_MODULE_USAGE(
"server=<address> "
@@ -86,15 +88,7 @@ PA_MODULE_USAGE(
PA_MODULE_AUTHOR("Lennart Poettering");
PA_MODULE_VERSION(PACKAGE_VERSION);
-
-#define DEFAULT_TLENGTH_MSEC 100
-#define DEFAULT_MINREQ_MSEC 10
-#define DEFAULT_MAXLENGTH_MSEC ((DEFAULT_TLENGTH_MSEC*3)/2)
-#define DEFAULT_FRAGSIZE_MSEC 10
-
-#define DEFAULT_TIMEOUT 5
-
-#define LATENCY_INTERVAL 10
+PA_MODULE_LOAD_ONCE(FALSE);
static const char* const valid_modargs[] = {
"server",
@@ -113,36 +107,58 @@ static const char* const valid_modargs[] = {
NULL,
};
-enum {
- SOURCE_MESSAGE_POST = PA_SOURCE_MESSAGE_MAX
-};
+#define DEFAULT_TIMEOUT 5
+
+#define LATENCY_INTERVAL 10
+
+#define MIN_NETWORK_LATENCY_USEC (8*PA_USEC_PER_MSEC)
+
+#ifdef TUNNEL_SINK
enum {
SINK_MESSAGE_REQUEST = PA_SINK_MESSAGE_MAX,
+ SINK_MESSAGE_REMOTE_SUSPEND,
+ SINK_MESSAGE_UPDATE_LATENCY,
SINK_MESSAGE_POST
};
+#define DEFAULT_TLENGTH_MSEC 150
+#define DEFAULT_MINREQ_MSEC 25
+
+#else
+
+enum {
+ SOURCE_MESSAGE_POST = PA_SOURCE_MESSAGE_MAX,
+ SOURCE_MESSAGE_REMOTE_SUSPEND,
+ SOURCE_MESSAGE_UPDATE_LATENCY
+};
+
+#define DEFAULT_FRAGSIZE_MSEC 25
+
+#endif
+
#ifdef TUNNEL_SINK
static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+static void command_started(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
#endif
static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
-static void command_overflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
-static void command_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
-static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+static void command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+static void command_suspended(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
static void command_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
#ifdef TUNNEL_SINK
[PA_COMMAND_REQUEST] = command_request,
+ [PA_COMMAND_STARTED] = command_started,
#endif
[PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event,
- [PA_COMMAND_OVERFLOW] = command_overflow,
- [PA_COMMAND_UNDERFLOW] = command_underflow,
+ [PA_COMMAND_OVERFLOW] = command_overflow_or_underflow,
+ [PA_COMMAND_UNDERFLOW] = command_overflow_or_underflow,
[PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed,
[PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed,
- [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = command_suspend,
- [PA_COMMAND_RECORD_STREAM_SUSPENDED] = command_suspend,
+ [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = command_suspended,
+ [PA_COMMAND_RECORD_STREAM_SUSPENDED] = command_suspended,
[PA_COMMAND_PLAYBACK_STREAM_MOVED] = command_moved,
[PA_COMMAND_RECORD_STREAM_MOVED] = command_moved,
};
@@ -163,7 +179,7 @@ struct userdata {
#ifdef TUNNEL_SINK
char *sink_name;
pa_sink *sink;
- uint32_t requested_bytes;
+ int32_t requested_bytes;
#else
char *source_name;
pa_source *source;
@@ -178,6 +194,14 @@ struct userdata {
int64_t counter, counter_delta;
+ pa_bool_t remote_corked:1;
+ pa_bool_t remote_suspended:1;
+
+ pa_usec_t transport_usec;
+ pa_bool_t transport_usec_valid;
+
+ uint32_t ignore_latency_before;
+
pa_time_event *time_event;
pa_bool_t auth_cookie_in_property;
@@ -198,7 +222,10 @@ struct userdata {
#endif
};
-static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+static void request_latency(struct userdata *u);
+
+/* Called from main context */
+static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
pa_assert(pd);
@@ -210,7 +237,8 @@ static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t comma
pa_module_unload_request(u->module);
}
-static void command_overflow(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+/* Called from main context */
+static void command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
pa_assert(pd);
@@ -218,21 +246,40 @@ static void command_overflow(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, P
pa_assert(u);
pa_assert(u->pdispatch == pd);
- pa_log_warn("Server signalled buffer overrun.");
+ pa_log_info("Server signalled buffer overrun/underrun.");
+ request_latency(u);
}
-static void command_underflow(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+/* Called from main context */
+static void command_suspended(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
+ uint32_t channel;
+ pa_bool_t suspended;
pa_assert(pd);
pa_assert(t);
pa_assert(u);
pa_assert(u->pdispatch == pd);
- pa_log_warn("Server signalled buffer underrun.");
+ if (pa_tagstruct_getu32(t, &channel) < 0 ||
+ pa_tagstruct_get_boolean(t, &suspended) < 0 ||
+ !pa_tagstruct_eof(t)) {
+ pa_log("Invalid packet");
+ pa_module_unload_request(u->module);
+ return;
+ }
+
+#ifdef TUNNEL_SINK
+ pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_REMOTE_SUSPEND, PA_UINT32_TO_PTR(!!suspended), 0, NULL);
+#else
+ pa_asyncmsgq_send(u->source->asyncmsgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_REMOTE_SUSPEND, PA_UINT32_TO_PTR(!!suspended), 0, NULL);
+#endif
+
+ request_latency(u);
}
-static void command_suspend(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+/* Called from main context */
+static void command_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
pa_assert(pd);
@@ -240,28 +287,54 @@ static void command_suspend(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA
pa_assert(u);
pa_assert(u->pdispatch == pd);
- pa_log_debug("Server reports a stream suspension.");
+ pa_log_debug("Server reports a stream move.");
+ request_latency(u);
}
-static void command_moved(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
- struct userdata *u = userdata;
+#ifdef TUNNEL_SINK
+
+/* 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;
pa_assert(pd);
pa_assert(t);
pa_assert(u);
pa_assert(u->pdispatch == pd);
- pa_log_debug("Server reports a stream move.");
+ pa_log_debug("Server reports playback started.");
+ request_latency(u);
}
-static void stream_cork(struct userdata *u, pa_bool_t cork) {
- pa_tagstruct *t;
+#endif
+
+/* Called from IO thread context */
+static void stream_cork_within_thread(struct userdata *u, pa_bool_t cork) {
+ pa_usec_t x;
pa_assert(u);
- if (cork)
- pa_smoother_pause(u->smoother, pa_rtclock_usec());
+ if (u->remote_corked == cork)
+ return;
+
+ u->remote_corked = cork;
+ x = pa_rtclock_usec();
+
+ /* Correct by the time this needs to travel to the other side.
+ * This is a valid thread-safe access, because the main thread is
+ * waiting for us */
+ if (u->transport_usec_valid)
+ x += u->transport_usec;
+
+ if (u->remote_suspended || u->remote_corked)
+ pa_smoother_pause(u->smoother, x);
else
- pa_smoother_resume(u->smoother, pa_rtclock_usec());
+ pa_smoother_resume(u->smoother, x);
+}
+
+/* Called from main context */
+static void stream_cork(struct userdata *u, pa_bool_t cork) {
+ pa_tagstruct *t;
+ pa_assert(u);
if (!u->pstream)
return;
@@ -276,19 +349,50 @@ static void stream_cork(struct userdata *u, pa_bool_t cork) {
pa_tagstruct_putu32(t, u->channel);
pa_tagstruct_put_boolean(t, !!cork);
pa_pstream_send_tagstruct(u->pstream, t);
+
+ request_latency(u);
+}
+
+/* Called from IO thread context */
+static void stream_suspend_within_thread(struct userdata *u, pa_bool_t suspend) {
+ pa_usec_t x;
+ pa_assert(u);
+
+ if (u->remote_suspended == suspend)
+ return;
+
+ u->remote_suspended = suspend;
+
+ x = pa_rtclock_usec();
+
+ /* Correct by the time this needed to travel from the other side.
+ * This is a valid thread-safe access, because the main thread is
+ * waiting for us */
+ if (u->transport_usec_valid)
+ x -= u->transport_usec;
+
+ if (u->remote_suspended || u->remote_corked)
+ pa_smoother_pause(u->smoother, x);
+ else
+ pa_smoother_resume(u->smoother, x);
}
#ifdef TUNNEL_SINK
+/* Called from IO thread context */
static void send_data(struct userdata *u) {
pa_assert(u);
while (u->requested_bytes > 0) {
pa_memchunk memchunk;
+
pa_sink_render(u->sink, u->requested_bytes, &memchunk);
pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_POST, NULL, 0, &memchunk, NULL);
pa_memblock_unref(memchunk.memblock);
+
u->requested_bytes -= memchunk.length;
+
+ u->counter += memchunk.length;
}
}
@@ -302,13 +406,27 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
int r;
/* First, change the state, because otherwide pa_sink_render() would fail */
- if ((r = pa_sink_process_msg(o, code, data, offset, chunk)) >= 0)
- if (PA_SINK_IS_OPENED((pa_sink_state_t) PA_PTR_TO_UINT(data)))
+ if ((r = pa_sink_process_msg(o, code, data, offset, chunk)) >= 0) {
+
+ stream_cork_within_thread(u, u->sink->state == PA_SINK_SUSPENDED);
+
+ if (PA_SINK_IS_OPENED(u->sink->state))
send_data(u);
+ }
return r;
}
+ case PA_SINK_MESSAGE_GET_LATENCY: {
+ pa_usec_t yl, yr, *usec = data;
+
+ yl = pa_bytes_to_usec(u->counter, &u->sink->sample_spec);
+ yr = pa_smoother_get(u->smoother, pa_rtclock_usec());
+
+ *usec = yl > yr ? yl - yr : 0;
+ return 0;
+ }
+
case SINK_MESSAGE_REQUEST:
pa_assert(offset > 0);
@@ -319,6 +437,28 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
return 0;
+
+ case SINK_MESSAGE_REMOTE_SUSPEND:
+
+ stream_suspend_within_thread(u, !!PA_PTR_TO_UINT(data));
+ return 0;
+
+
+ case SINK_MESSAGE_UPDATE_LATENCY: {
+ pa_usec_t y;
+
+ y = pa_bytes_to_usec(u->counter, &u->sink->sample_spec);
+
+ if (y > (pa_usec_t) offset || offset < 0)
+ y -= offset;
+ else
+ y = 0;
+
+ pa_smoother_put(u->smoother, pa_rtclock_usec(), y);
+
+ return 0;
+ }
+
case SINK_MESSAGE_POST:
/* OK, This might be a bit confusing. This message is
@@ -327,14 +467,16 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
* dispatched. Yeah, ugly, but I am a lazy bastard. */
pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, chunk);
- u->counter += chunk->length;
+
u->counter_delta += chunk->length;
+
return 0;
}
return pa_sink_process_msg(o, code, data, offset, chunk);
}
+/* Called from main context */
static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
struct userdata *u;
pa_sink_assert_ref(s);
@@ -363,20 +505,65 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
#else
+/* This function is called from IO context -- except when it is not. */
static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
struct userdata *u = PA_SOURCE(o)->userdata;
switch (code) {
+
+ case PA_SINK_MESSAGE_SET_STATE: {
+ int r;
+
+ if ((r = pa_sink_process_msg(o, code, data, offset, chunk)) >= 0)
+ stream_cork_within_thread(u, u->source->state == PA_SOURCE_SUSPENDED);
+
+ return r;
+ }
+
+ case PA_SOURCE_MESSAGE_GET_LATENCY: {
+ pa_usec_t yr, yl, *usec = data;
+
+ yl = pa_bytes_to_usec(u->counter, &PA_SINK(o)->sample_spec);
+ yr = pa_smoother_get(u->smoother, pa_rtclock_usec());
+
+ *usec = yr > yl ? yr - yl : 0;
+ return 0;
+ }
+
case SOURCE_MESSAGE_POST:
if (PA_SOURCE_IS_OPENED(u->source->thread_info.state))
pa_source_post(u->source, chunk);
+
+ u->counter += chunk->length;
+
return 0;
+
+ case SOURCE_MESSAGE_REMOTE_SUSPEND:
+
+ stream_suspend_within_thread(u, !!PA_PTR_TO_UINT(data));
+ return 0;
+
+ case SOURCE_MESSAGE_UPDATE_LATENCY: {
+ pa_usec_t y;
+
+ y = pa_bytes_to_usec(u->counter, &u->source->sample_spec);
+
+ if (offset >= 0 || y > (pa_usec_t) -offset)
+ y += offset;
+ else
+ y = 0;
+
+ pa_smoother_put(u->smoother, pa_rtclock_usec(), y);
+
+ return 0;
+ }
}
return pa_source_process_msg(o, code, data, offset, chunk);
}
+/* Called from main context */
static int source_set_state(pa_source *s, pa_source_state_t state) {
struct userdata *u;
pa_source_assert_ref(s);
@@ -436,7 +623,8 @@ finish:
}
#ifdef TUNNEL_SINK
-static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+/* Called from main context */
+static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
uint32_t bytes, channel;
@@ -457,7 +645,7 @@ static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ui
goto fail;
}
- pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_REQUEST, NULL, bytes, NULL);
+ pa_asyncmsgq_post(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_REQUEST, NULL, bytes, NULL, NULL);
return;
fail:
@@ -466,12 +654,15 @@ fail:
#endif
-static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+/* Called from main context */
+static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
- pa_usec_t sink_usec, source_usec, transport_usec, host_usec, k;
- int playing;
+ pa_usec_t sink_usec, source_usec, transport_usec;
+ pa_bool_t playing;
int64_t write_index, read_index;
struct timeval local, remote, now;
+ pa_sample_spec *ss;
+ int64_t delay;
pa_assert(pd);
pa_assert(u);
@@ -480,7 +671,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G
if (command == PA_COMMAND_ERROR)
pa_log("Failed to get latency.");
else
- pa_log("Protocol error 1.");
+ pa_log("Protocol error.");
goto fail;
}
@@ -491,52 +682,90 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G
pa_tagstruct_get_timeval(t, &remote) < 0 ||
pa_tagstruct_gets64(t, &write_index) < 0 ||
pa_tagstruct_gets64(t, &read_index) < 0) {
- pa_log("Invalid reply. (latency)");
+ pa_log("Invalid reply.");
goto fail;
}
+#ifdef TUNNEL_SINK
+ if (u->version >= 13) {
+ uint64_t underrun_for = 0, playing_for = 0;
+
+ if (pa_tagstruct_getu64(t, &underrun_for) < 0 ||
+ pa_tagstruct_getu64(t, &playing_for) < 0) {
+ pa_log("Invalid reply.");
+ goto fail;
+ }
+ }
+#endif
+
+ if (!pa_tagstruct_eof(t)) {
+ pa_log("Invalid reply.");
+ goto fail;
+ }
+
+ if (tag < u->ignore_latency_before) {
+ request_latency(u);
+ return;
+ }
+
pa_gettimeofday(&now);
+ /* Calculate transport usec */
if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) {
/* local and remote seem to have synchronized clocks */
#ifdef TUNNEL_SINK
- transport_usec = pa_timeval_diff(&remote, &local);
+ u->transport_usec = pa_timeval_diff(&remote, &local);
#else
- transport_usec = pa_timeval_diff(&now, &remote);
+ u->transport_usec = pa_timeval_diff(&now, &remote);
#endif
} else
- transport_usec = pa_timeval_diff(&now, &local)/2;
+ u->transport_usec = pa_timeval_diff(&now, &local)/2;
+ u->transport_usec_valid = TRUE;
+ /* First, take the device's delay */
#ifdef TUNNEL_SINK
- host_usec = sink_usec + transport_usec;
+ delay = (int64_t) sink_usec;
+ ss = &u->sink->sample_spec;
#else
- host_usec = source_usec + transport_usec;
- if (host_usec > sink_usec)
- host_usec -= sink_usec;
- else
- host_usec = 0;
+ delay = (int64_t) source_usec;
+ ss = &u->source->sample_spec;
#endif
+ /* Add the length of our server-side buffer */
+ if (write_index >= read_index)
+ delay += (int64_t) pa_bytes_to_usec(write_index-read_index, ss);
+ else
+ delay -= (int64_t) pa_bytes_to_usec(read_index-write_index, ss);
+
+ /* Our measurements are already out of date, hence correct by the *
+ * transport latency */
#ifdef TUNNEL_SINK
- k = pa_bytes_to_usec(u->counter - u->counter_delta, &u->sink->sample_spec);
+ delay -= (int64_t) transport_usec;
+#else
+ delay += (int64_t) transport_usec;
+#endif
- if (k > host_usec)
- k -= host_usec;
- else
- k = 0;
+ /* Now correct by what we have have read/written since we requested the update */
+#ifdef TUNNEL_SINK
+ delay += (int64_t) pa_bytes_to_usec(u->counter_delta, ss);
#else
- k = pa_bytes_to_usec(u->counter - u->counter_delta, &u->source->sample_spec);
- k += host_usec;
+ delay -= (int64_t) pa_bytes_to_usec(u->counter_delta, ss);
#endif
- pa_smoother_put(u->smoother, pa_rtclock_usec(), k);
+#ifdef TUNNEL_SINK
+ pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_UPDATE_LATENCY, 0, delay, NULL);
+#else
+ pa_asyncmsgq_send(u->source->asyncmsgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_UPDATE_LATENCY, 0, delay, NULL);
+#endif
return;
fail:
+
pa_module_unload_request(u->module);
}
+/* Called from main context */
static void request_latency(struct userdata *u) {
pa_tagstruct *t;
struct timeval now;
@@ -558,10 +787,12 @@ static void request_latency(struct userdata *u) {
pa_pstream_send_tagstruct(u->pstream, t);
pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u, NULL);
+ u->ignore_latency_before = tag;
u->counter_delta = 0;
}
-static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
+/* Called from main context */
+static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, const struct timeval *tv, void *userdata) {
struct userdata *u = userdata;
struct timeval ntv;
@@ -576,32 +807,7 @@ static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED
m->time_restart(e, &ntv);
}
-#ifdef TUNNEL_SINK
-/* static pa_usec_t sink_get_latency(pa_sink *s) { */
-/* pa_usec_t t, c; */
-/* struct userdata *u = s->userdata; */
-
-/* pa_sink_assert_ref(s); */
-
-/* c = pa_bytes_to_usec(u->counter, &s->sample_spec); */
-/* t = pa_smoother_get(u->smoother, pa_rtclock_usec()); */
-
-/* return c > t ? c - t : 0; */
-/* } */
-#else
-/* static pa_usec_t source_get_latency(pa_source *s) { */
-/* pa_usec_t t, c; */
-/* struct userdata *u = s->userdata; */
-
-/* pa_source_assert_ref(s); */
-
-/* c = pa_bytes_to_usec(u->counter, &s->sample_spec); */
-/* t = pa_smoother_get(u->smoother, pa_rtclock_usec()); */
-
-/* return t > c ? t - c : 0; */
-/* } */
-#endif
-
+/* Called from main context */
static void update_description(struct userdata *u) {
char *d;
char un[128], hn[128];
@@ -616,8 +822,14 @@ static void update_description(struct userdata *u) {
#ifdef TUNNEL_SINK
pa_sink_set_description(u->sink, d);
+ pa_proplist_sets(u->sink->proplist, "tunnel.remote.user", u->user_name);
+ pa_proplist_sets(u->sink->proplist, "tunnel.remote.fqdn", u->server_fqdn);
+ pa_proplist_sets(u->sink->proplist, "tunnel.remote.description", u->device_description);
#else
pa_source_set_description(u->source, d);
+ pa_proplist_sets(u->source->proplist, "tunnel.remote.user", u->user_name);
+ pa_proplist_sets(u->source->proplist, "tunnel.remote.fqdn", u->server_fqdn);
+ pa_proplist_sets(u->source->proplist, "tunnel.remote.description", u->device_description);
#endif
pa_xfree(d);
@@ -640,7 +852,8 @@ static void update_description(struct userdata *u) {
pa_xfree(d);
}
-static void server_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+/* Called from main context */
+static void server_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
pa_sample_spec ss;
const char *server_name, *server_version, *user_name, *host_name, *default_sink_name, *default_source_name;
@@ -653,7 +866,7 @@ static void server_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uin
if (command == PA_COMMAND_ERROR)
pa_log("Failed to get info.");
else
- pa_log("Protocol error 6.");
+ pa_log("Protocol error.");
goto fail;
}
@@ -665,7 +878,13 @@ static void server_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uin
pa_tagstruct_gets(t, &default_sink_name) < 0 ||
pa_tagstruct_gets(t, &default_source_name) < 0 ||
pa_tagstruct_getu32(t, &cookie) < 0) {
- pa_log("Invalid reply. (get_server_info)");
+
+ pa_log("Parse failure");
+ goto fail;
+ }
+
+ if (!pa_tagstruct_eof(t)) {
+ pa_log("Packet too long");
goto fail;
}
@@ -685,24 +904,28 @@ fail:
#ifdef TUNNEL_SINK
-static void sink_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+/* Called from main context */
+static void sink_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
uint32_t idx, owner_module, monitor_source, flags;
const char *name, *description, *monitor_source_name, *driver;
pa_sample_spec ss;
pa_channel_map cm;
pa_cvolume volume;
- int mute;
+ pa_bool_t mute;
pa_usec_t latency;
+ pa_proplist *pl;
pa_assert(pd);
pa_assert(u);
+ pl = pa_proplist_new();
+
if (command != PA_COMMAND_REPLY) {
if (command == PA_COMMAND_ERROR)
pa_log("Failed to get info.");
else
- pa_log("Protocol error 5.");
+ pa_log("Protocol error.");
goto fail;
}
@@ -719,10 +942,29 @@ static void sink_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint3
pa_tagstruct_get_usec(t, &latency) < 0 ||
pa_tagstruct_gets(t, &driver) < 0 ||
pa_tagstruct_getu32(t, &flags) < 0) {
- pa_log("Invalid reply. (get_sink_info)");
+
+ pa_log("Parse failure");
goto fail;
}
+ if (u->version >= 13) {
+ pa_usec_t configured_latency;
+
+ if (pa_tagstruct_get_proplist(t, pl) < 0 ||
+ pa_tagstruct_get_usec(t, &configured_latency) < 0) {
+
+ pa_log("Parse failure");
+ goto fail;
+ }
+ }
+
+ if (!pa_tagstruct_eof(t)) {
+ pa_log("Packet too long");
+ goto fail;
+ }
+
+ pa_proplist_free(pl);
+
if (!u->sink_name || strcmp(name, u->sink_name))
return;
@@ -735,26 +977,31 @@ static void sink_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint3
fail:
pa_module_unload_request(u->module);
+ pa_proplist_free(pl);
}
-static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+/* Called from main context */
+static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
uint32_t idx, owner_module, client, sink;
pa_usec_t buffer_usec, sink_usec;
const char *name, *driver, *resample_method;
- int mute;
+ pa_bool_t mute;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
pa_cvolume volume;
+ pa_proplist *pl;
pa_assert(pd);
pa_assert(u);
+ pl = pa_proplist_new();
+
if (command != PA_COMMAND_REPLY) {
if (command == PA_COMMAND_ERROR)
pa_log("Failed to get info.");
else
- pa_log("Protocol error 2.");
+ pa_log("Protocol error.");
goto fail;
}
@@ -769,12 +1016,35 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED
pa_tagstruct_get_usec(t, &buffer_usec) < 0 ||
pa_tagstruct_get_usec(t, &sink_usec) < 0 ||
pa_tagstruct_gets(t, &resample_method) < 0 ||
- pa_tagstruct_gets(t, &driver) < 0 ||
- (u->version >= 11 && pa_tagstruct_get_boolean(t, &mute) < 0)) {
- pa_log("Invalid reply. (get_info)");
+ pa_tagstruct_gets(t, &driver) < 0) {
+
+ pa_log("Parse failure");
goto fail;
}
+ if (u->version >= 11) {
+ if (pa_tagstruct_get_boolean(t, &mute) < 0) {
+
+ pa_log("Parse failure");
+ goto fail;
+ }
+ }
+
+ if (u->version >= 13) {
+ if (pa_tagstruct_get_proplist(t, pl) < 0) {
+
+ pa_log("Parse failure");
+ goto fail;
+ }
+ }
+
+ if (!pa_tagstruct_eof(t)) {
+ pa_log("Packet too long");
+ goto fail;
+ }
+
+ pa_proplist_free(pl);
+
if (idx != u->device_index)
return;
@@ -794,28 +1064,33 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED
fail:
pa_module_unload_request(u->module);
+ pa_proplist_free(pl);
}
#else
-static void source_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+/* Called from main context */
+static void source_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
uint32_t idx, owner_module, monitor_of_sink, flags;
const char *name, *description, *monitor_of_sink_name, *driver;
pa_sample_spec ss;
pa_channel_map cm;
pa_cvolume volume;
- int mute;
- pa_usec_t latency;
+ pa_bool_t mute;
+ pa_usec_t latency, configured_latency;
+ pa_proplist *pl;
pa_assert(pd);
pa_assert(u);
+ pl = pa_proplist_new();
+
if (command != PA_COMMAND_REPLY) {
if (command == PA_COMMAND_ERROR)
pa_log("Failed to get info.");
else
- pa_log("Protocol error 5.");
+ pa_log("Protocol error.");
goto fail;
}
@@ -832,10 +1107,27 @@ static void source_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uin
pa_tagstruct_get_usec(t, &latency) < 0 ||
pa_tagstruct_gets(t, &driver) < 0 ||
pa_tagstruct_getu32(t, &flags) < 0) {
- pa_log("Invalid reply. (get_source_info)");
+
+ pa_log("Parse failure");
goto fail;
}
+ if (u->version >= 13) {
+ if (pa_tagstruct_get_proplist(t, pl) < 0 ||
+ pa_tagstruct_get_usec(t, &configured_latency) < 0) {
+
+ pa_log("Parse failure");
+ goto fail;
+ }
+ }
+
+ if (!pa_tagstruct_eof(t)) {
+ pa_log("Packet too long");
+ goto fail;
+ }
+
+ pa_proplist_free(pl);
+
if (!u->source_name || strcmp(name, u->source_name))
return;
@@ -848,10 +1140,12 @@ static void source_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uin
fail:
pa_module_unload_request(u->module);
+ pa_proplist_free(pl);
}
#endif
+/* Called from main context */
static void request_info(struct userdata *u) {
pa_tagstruct *t;
uint32_t tag;
@@ -871,25 +1165,30 @@ static void request_info(struct userdata *u) {
pa_pstream_send_tagstruct(u->pstream, t);
pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, sink_input_info_cb, u, NULL);
- t = pa_tagstruct_new(NULL, 0);
- pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO);
- pa_tagstruct_putu32(t, tag = u->ctag++);
- pa_tagstruct_putu32(t, PA_INVALID_INDEX);
- pa_tagstruct_puts(t, u->sink_name);
- pa_pstream_send_tagstruct(u->pstream, t);
- pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, sink_info_cb, u, NULL);
+ if (u->sink_name) {
+ t = pa_tagstruct_new(NULL, 0);
+ pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO);
+ pa_tagstruct_putu32(t, tag = u->ctag++);
+ pa_tagstruct_putu32(t, PA_INVALID_INDEX);
+ pa_tagstruct_puts(t, u->sink_name);
+ pa_pstream_send_tagstruct(u->pstream, t);
+ pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, sink_info_cb, u, NULL);
+ }
#else
- t = pa_tagstruct_new(NULL, 0);
- pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO);
- pa_tagstruct_putu32(t, tag = u->ctag++);
- pa_tagstruct_putu32(t, PA_INVALID_INDEX);
- pa_tagstruct_puts(t, u->source_name);
- pa_pstream_send_tagstruct(u->pstream, t);
- pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, source_info_cb, u, NULL);
+ if (u->source_name) {
+ t = pa_tagstruct_new(NULL, 0);
+ pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO);
+ pa_tagstruct_putu32(t, tag = u->ctag++);
+ pa_tagstruct_putu32(t, PA_INVALID_INDEX);
+ pa_tagstruct_puts(t, u->source_name);
+ pa_pstream_send_tagstruct(u->pstream, t);
+ pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, source_info_cb, u, NULL);
+ }
#endif
}
-static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+/* Called from main context */
+static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
pa_subscription_event_type_t e;
uint32_t idx;
@@ -919,6 +1218,7 @@ static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t com
request_info(u);
}
+/* Called from main context */
static void start_subscribe(struct userdata *u) {
pa_tagstruct *t;
uint32_t tag;
@@ -938,7 +1238,8 @@ static void start_subscribe(struct userdata *u) {
pa_pstream_send_tagstruct(u->pstream, t);
}
-static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
+/* Called from main context */
+static void create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
struct timeval ntv;
#ifdef TUNNEL_SINK
@@ -953,7 +1254,7 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN
if (command == PA_COMMAND_ERROR)
pa_log("Failed to create stream.");
else
- pa_log("Protocol error 3.");
+ pa_log("Protocol error.");
goto fail;
}
@@ -967,22 +1268,57 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN
if (u->version >= 9) {
#ifdef TUNNEL_SINK
- uint32_t maxlength, tlength, prebuf, minreq;
+ if (pa_tagstruct_getu32(t, &u->maxlength) < 0 ||
+ pa_tagstruct_getu32(t, &u->tlength) < 0 ||
+ pa_tagstruct_getu32(t, &u->prebuf) < 0 ||
+ pa_tagstruct_getu32(t, &u->minreq) < 0)
+ goto parse_error;
+#else
+ if (pa_tagstruct_getu32(t, &u->maxlength) < 0 ||
+ pa_tagstruct_getu32(t, &u->fragsize) < 0)
+ goto parse_error;
+#endif
+ }
- if (pa_tagstruct_getu32(t, &maxlength) < 0 ||
- pa_tagstruct_getu32(t, &tlength) < 0 ||
- pa_tagstruct_getu32(t, &prebuf) < 0 ||
- pa_tagstruct_getu32(t, &minreq) < 0)
+ if (u->version >= 12) {
+ pa_sample_spec ss;
+ pa_channel_map cm;
+ uint32_t device_index;
+ const char *dn;
+ pa_bool_t suspended;
+
+ if (pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
+ pa_tagstruct_get_channel_map(t, &cm) < 0 ||
+ pa_tagstruct_getu32(t, &device_index) < 0 ||
+ pa_tagstruct_gets(t, &dn) < 0 ||
+ pa_tagstruct_get_boolean(t, &suspended) < 0)
goto parse_error;
+
+#ifdef TUNNEL_SINK
+ pa_xfree(u->sink_name);
+ u->sink_name = pa_xstrdup(dn);
#else
- uint32_t maxlength, fragsize;
+ pa_xfree(u->source_name);
+ u->source_name = pa_xstrdup(dn);
+#endif
+ }
+
+ if (u->version >= 13) {
+ pa_usec_t usec;
- if (pa_tagstruct_getu32(t, &maxlength) < 0 ||
- pa_tagstruct_getu32(t, &fragsize) < 0)
+ if (pa_tagstruct_get_usec(t, &usec) < 0)
goto parse_error;
+
+#ifdef TUNNEL_SINK
+ pa_sink_set_latency_range(u->sink, usec + MIN_NETWORK_LATENCY_USEC, 0);
+#else
+ pa_source_set_latency_range(u->source, usec + MIN_NETWORK_LATENCY_USEC, 0);
#endif
}
+ if (!pa_tagstruct_eof(t))
+ goto parse_error;
+
start_subscribe(u);
request_info(u);
@@ -1006,8 +1342,10 @@ parse_error:
fail:
pa_module_unload_request(u->module);
+
}
+/* Called from main context */
static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
struct userdata *u = userdata;
pa_tagstruct *reply;
@@ -1021,11 +1359,13 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
pa_assert(u->pdispatch == pd);
if (command != PA_COMMAND_REPLY ||
- pa_tagstruct_getu32(t, &u->version) < 0) {
+ pa_tagstruct_getu32(t, &u->version) < 0 ||
+ !pa_tagstruct_eof(t)) {
+
if (command == PA_COMMAND_ERROR)
pa_log("Failed to authenticate");
else
- pa_log("Protocol error 4.");
+ pa_log("Protocol error.");
goto fail;
}
@@ -1036,6 +1376,15 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
goto fail;
}
+ /* Starting with protocol version 13 the MSB of the version tag
+ reflects if shm is enabled for this connection or not. We don't
+ support SHM here at all, so we just ignore this. */
+
+ if (u->version >= 13)
+ u->version &= 0x7FFFFFFFU;
+
+ pa_log_debug("Protocol version: remote %u, local %u", u->version, PA_PROTOCOL_VERSION);
+
#ifdef TUNNEL_SINK
pa_snprintf(name, sizeof(name), "%s for %s@%s",
u->sink_name,
@@ -1051,16 +1400,42 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
reply = pa_tagstruct_new(NULL, 0);
pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME);
pa_tagstruct_putu32(reply, tag = u->ctag++);
- pa_tagstruct_puts(reply, "PulseAudio");
+
+ if (u->version >= 13) {
+ pa_proplist *pl;
+ pl = pa_proplist_new();
+ pa_init_proplist(pl);
+ pa_proplist_sets(pl, PA_PROP_APPLICATION_ID, "org.PulseAudio.PulseAudio");
+ pa_proplist_sets(pl, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION);
+ pa_tagstruct_put_proplist(reply, pl);
+ pa_proplist_free(pl);
+ } else
+ pa_tagstruct_puts(reply, "PulseAudio");
+
pa_pstream_send_tagstruct(u->pstream, reply);
/* We ignore the server's reply here */
reply = pa_tagstruct_new(NULL, 0);
+ if (u->version < 13)
+ /* Only for older PA versions we need to fill in the maxlength */
+ u->maxlength = 4*1024*1024;
+
+#ifdef TUNNEL_SINK
+ u->tlength = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_TLENGTH_MSEC, &u->sink->sample_spec);
+ u->minreq = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_MINREQ_MSEC, &u->sink->sample_spec);
+ u->prebuf = u->tlength;
+#else
+ u->fragsize = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_FRAGSIZE_MSEC, &u->source->sample_spec);
+#endif
+
#ifdef TUNNEL_SINK
pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM);
pa_tagstruct_putu32(reply, tag = u->ctag++);
- pa_tagstruct_puts(reply, name);
+
+ if (u->version < 13)
+ pa_tagstruct_puts(reply, name);
+
pa_tagstruct_put_sample_spec(reply, &u->sink->sample_spec);
pa_tagstruct_put_channel_map(reply, &u->sink->channel_map);
pa_tagstruct_putu32(reply, PA_INVALID_INDEX);
@@ -1076,7 +1451,10 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
#else
pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_RECORD_STREAM);
pa_tagstruct_putu32(reply, tag = u->ctag++);
- pa_tagstruct_puts(reply, name);
+
+ if (u->version < 13)
+ pa_tagstruct_puts(reply, name);
+
pa_tagstruct_put_sample_spec(reply, &u->source->sample_spec);
pa_tagstruct_put_channel_map(reply, &u->source->channel_map);
pa_tagstruct_putu32(reply, PA_INVALID_INDEX);
@@ -1086,16 +1464,31 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
pa_tagstruct_putu32(reply, u->fragsize);
#endif
- /* New flags added in 0.9.8 */
if (u->version >= 12) {
- /* TODO: set these to useful values */
- pa_tagstruct_put_boolean(reply, FALSE); /*no_remap*/
- pa_tagstruct_put_boolean(reply, FALSE); /*no_remix*/
- pa_tagstruct_put_boolean(reply, FALSE); /*fix_format*/
- pa_tagstruct_put_boolean(reply, FALSE); /*fix_rate*/
- pa_tagstruct_put_boolean(reply, FALSE); /*fix_channels*/
- pa_tagstruct_put_boolean(reply, FALSE); /*no_move*/
- pa_tagstruct_put_boolean(reply, FALSE); /*variable_rate*/
+ pa_tagstruct_put_boolean(reply, FALSE); /* no_remap */
+ pa_tagstruct_put_boolean(reply, FALSE); /* no_remix */
+ pa_tagstruct_put_boolean(reply, FALSE); /* fix_format */
+ pa_tagstruct_put_boolean(reply, FALSE); /* fix_rate */
+ pa_tagstruct_put_boolean(reply, FALSE); /* fix_channels */
+ pa_tagstruct_put_boolean(reply, TRUE); /* no_move */
+ pa_tagstruct_put_boolean(reply, FALSE); /* variable_rate */
+ }
+
+ if (u->version >= 13) {
+ pa_proplist *pl;
+
+ pa_tagstruct_put_boolean(reply, FALSE); /* start muted/peak detect*/
+ pa_tagstruct_put_boolean(reply, TRUE); /* adjust_latency */
+
+ pl = pa_proplist_new();
+ pa_proplist_sets(pl, PA_PROP_MEDIA_NAME, name);
+ pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "abstract");
+ pa_tagstruct_put_proplist(reply, pl);
+ pa_proplist_free(pl);
+
+#ifndef TUNNEL_SINK
+ pa_tagstruct_putu32(reply, PA_INVALID_INDEX); /* direct on input */
+#endif
}
pa_pstream_send_tagstruct(u->pstream, reply);
@@ -1109,6 +1502,7 @@ fail:
pa_module_unload_request(u->module);
}
+/* Called from main context */
static void pstream_die_callback(pa_pstream *p, void *userdata) {
struct userdata *u = userdata;
@@ -1119,6 +1513,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) {
pa_module_unload_request(u->module);
}
+/* Called from main context */
static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
struct userdata *u = userdata;
@@ -1134,6 +1529,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_c
}
#ifndef TUNNEL_SINK
+/* Called from main context */
static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) {
struct userdata *u = userdata;
@@ -1149,12 +1545,12 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
pa_asyncmsgq_send(u->source->asyncmsgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_POST, PA_UINT_TO_PTR(seek), offset, chunk);
- u->counter += chunk->length;
u->counter_delta += chunk->length;
}
#endif
+/* Called from main context */
static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata) {
struct userdata *u = userdata;
pa_tagstruct *t;
@@ -1211,10 +1607,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata
#ifdef TUNNEL_SINK
-static int sink_get_volume(pa_sink *sink) {
- return 0;
-}
-
+/* Called from main context */
static int sink_set_volume(pa_sink *sink) {
struct userdata *u;
pa_tagstruct *t;
@@ -1234,10 +1627,7 @@ static int sink_set_volume(pa_sink *sink) {
return 0;
}
-static int sink_get_mute(pa_sink *sink) {
- return 0;
-}
-
+/* Called from main context */
static int sink_set_mute(pa_sink *sink) {
struct userdata *u;
pa_tagstruct *t;
@@ -1262,6 +1652,7 @@ static int sink_set_mute(pa_sink *sink) {
#endif
+/* Called from main context */
static int load_key(struct userdata *u, const char*fn) {
pa_assert(u);
@@ -1293,7 +1684,7 @@ int pa__init(pa_module*m) {
struct userdata *u = NULL;
pa_sample_spec ss;
pa_channel_map map;
- char *t, *dn = NULL;
+ char *dn = NULL;
#ifdef TUNNEL_SINK
pa_sink_new_data data;
#else
@@ -1303,14 +1694,13 @@ int pa__init(pa_module*m) {
pa_assert(m);
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
- pa_log("failed to parse module arguments");
+ pa_log("Failed to parse module arguments");
goto fail;
}
- u = pa_xnew0(struct userdata, 1);
- m->userdata = u;
- u->module = m;
+ m->userdata = u = pa_xnew0(struct userdata, 1);
u->core = m->core;
+ u->module = m;
u->client = NULL;
u->pdispatch = NULL;
u->pstream = NULL;
@@ -1328,6 +1718,11 @@ int pa__init(pa_module*m) {
u->device_index = u->channel = PA_INVALID_INDEX;
u->auth_cookie_in_property = FALSE;
u->time_event = NULL;
+ u->ignore_latency_before = 0;
+ u->transport_usec = 0;
+ u->transport_usec_valid = FALSE;
+ u->remote_suspended = u->remote_corked = FALSE;
+ u->counter = u->counter_delta = 0;
u->rtpoll = pa_rtpoll_new();
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
@@ -1336,18 +1731,18 @@ int pa__init(pa_module*m) {
goto fail;
if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) {
- pa_log("no server specified.");
+ pa_log("No server specified.");
goto fail;
}
ss = m->core->default_sample_spec;
if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
- pa_log("invalid sample format specification");
+ pa_log("Invalid sample format specification");
goto fail;
}
if (!(u->client = pa_socket_client_new_string(m->core->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) {
- pa_log("failed to connect to server '%s'", u->server_name);
+ pa_log("Failed to connect to server '%s'", u->server_name);
goto fail;
}
@@ -1365,6 +1760,10 @@ int pa__init(pa_module*m) {
pa_sink_new_data_set_name(&data, dn);
pa_sink_new_data_set_sample_spec(&data, &ss);
pa_sink_new_data_set_channel_map(&data, &map);
+ pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "%s%s%s", pa_strempty(u->sink_name), u->sink_name ? " on " : "", u->server_name);
+ pa_proplist_sets(data.proplist, "tunnel.remote.server", u->server_name);
+ if (u->sink_name)
+ pa_proplist_sets(data.proplist, "tunnel.remote.sink", u->sink_name);
u->sink = pa_sink_new(m->core, &data, PA_SINK_NETWORK|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL);
pa_sink_new_data_done(&data);
@@ -1377,16 +1776,15 @@ int pa__init(pa_module*m) {
u->sink->parent.process_msg = sink_process_msg;
u->sink->userdata = u;
u->sink->set_state = sink_set_state;
-/* u->sink->get_latency = sink_get_latency; */
- u->sink->get_volume = sink_get_volume;
- u->sink->get_mute = sink_get_mute;
u->sink->set_volume = sink_set_volume;
u->sink->set_mute = sink_set_mute;
+ u->sink->refresh_volume = u->sink->refresh_muted = FALSE;
+
+ pa_sink_set_latency_range(u->sink, MIN_NETWORK_LATENCY_USEC, 0);
+
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
pa_sink_set_rtpoll(u->sink, u->rtpoll);
- pa_sink_set_description(u->sink, t = pa_sprintf_malloc("%s%s%s", u->sink_name ? u->sink_name : "", u->sink_name ? " on " : "", u->server_name));
- pa_xfree(t);
#else
@@ -1400,6 +1798,10 @@ int pa__init(pa_module*m) {
pa_source_new_data_set_name(&data, dn);
pa_source_new_data_set_sample_spec(&data, &ss);
pa_source_new_data_set_channel_map(&data, &map);
+ pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "%s%s%s", pa_strempty(u->source_name), u->source_name ? " on " : "", u->server_name);
+ pa_proplist_sets(data.proplist, "tunnel.remote.server", u->server_name);
+ if (u->source_name)
+ pa_proplist_sets(data.proplist, "tunnel.remote.source", u->source_name);
u->source = pa_source_new(m->core, &data, PA_SOURCE_NETWORK|PA_SOURCE_LATENCY);
pa_source_new_data_done(&data);
@@ -1410,30 +1812,26 @@ int pa__init(pa_module*m) {
}
u->source->parent.process_msg = source_process_msg;
- u->source->userdata = u;
u->source->set_state = source_set_state;
-/* u->source->get_latency = source_get_latency; */
+ u->source->userdata = u;
+
+ pa_source_set_latency_range(u->source, MIN_NETWORK_LATENCY_USEC, 0);
pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
pa_source_set_rtpoll(u->source, u->rtpoll);
- pa_source_set_description(u->source, t = pa_sprintf_malloc("%s%s%s", u->source_name ? u->source_name : "", u->source_name ? " on " : "", u->server_name));
- pa_xfree(t);
#endif
pa_xfree(dn);
u->time_event = NULL;
- u->maxlength = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_MAXLENGTH_MSEC, &ss);
+ u->maxlength = 0;
#ifdef TUNNEL_SINK
- u->tlength = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_TLENGTH_MSEC, &ss);
- u->minreq = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_MINREQ_MSEC, &ss);
- u->prebuf = u->tlength;
+ u->tlength = u->minreq = u->prebuf = 0;
#else
- u->fragsize = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_FRAGSIZE_MSEC, &ss);
+ u->fragsize = 0;
#endif
- u->counter = u->counter_delta = 0;
pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec());
if (!(u->thread = pa_thread_new(thread_func, u))) {
diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c
index 336bcac9..d862c203 100644
--- a/src/modules/module-volume-restore.c
+++ b/src/modules/module-volume-restore.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -102,7 +100,7 @@ static pa_cvolume* parse_volume(const char *s, pa_cvolume *v) {
return NULL;
k = strtol(s, &p, 0);
- if (k <= 0 || k > PA_CHANNELS_MAX)
+ if (k <= 0 || k > (long) PA_CHANNELS_MAX)
return NULL;
v->channels = (unsigned) k;
@@ -488,7 +486,6 @@ int pa__init(pa_module*m) {
u = pa_xnew(struct userdata, 1);
u->core = m->core;
u->hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
- u->table_file = pa_runtime_path(pa_modargs_get_value(ma, "table", DEFAULT_VOLUME_TABLE_FILE));
u->modified = FALSE;
u->subscription = NULL;
u->sink_input_new_hook_slot = u->sink_input_fixate_hook_slot = u->source_output_new_hook_slot = NULL;
@@ -496,6 +493,9 @@ int pa__init(pa_module*m) {
m->userdata = u;
+ if (!(u->table_file = pa_state_path(pa_modargs_get_value(ma, "table", DEFAULT_VOLUME_TABLE_FILE))))
+ goto fail;
+
if (pa_modargs_get_value_boolean(ma, "restore_device", &restore_device) < 0 ||
pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0) {
pa_log("restore_volume= and restore_device= expect boolean arguments");
@@ -513,12 +513,12 @@ int pa__init(pa_module*m) {
u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u);
if (restore_device) {
- u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], (pa_hook_cb_t) sink_input_new_hook_callback, u);
- u->source_output_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], (pa_hook_cb_t) source_output_new_hook_callback, u);
+ u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_new_hook_callback, u);
+ u->source_output_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_new_hook_callback, u);
}
if (restore_volume)
- u->sink_input_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], (pa_hook_cb_t) sink_input_fixate_hook_callback, u);
+ u->sink_input_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_fixate_hook_callback, u);
pa_modargs_free(ma);
return 0;
diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c
index f8bae02f..b452c3bf 100644
--- a/src/modules/module-waveout.c
+++ b/src/modules/module-waveout.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/module-x11-bell.c b/src/modules/module-x11-bell.c
index 761b82a9..f7be48f7 100644
--- a/src/modules/module-x11-bell.c
+++ b/src/modules/module-x11-bell.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -45,14 +43,24 @@
#include "module-x11-bell-symdef.h"
PA_MODULE_AUTHOR("Lennart Poettering");
-PA_MODULE_DESCRIPTION("X11 Bell interceptor");
+PA_MODULE_DESCRIPTION("X11 bell interceptor");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE("sink=<sink to connect to> sample=<sample name> display=<X11 display>");
+static const char* const valid_modargs[] = {
+ "sink",
+ "sample",
+ "display",
+ NULL
+};
+
struct userdata {
pa_core *core;
+ pa_module *module;
+
int xkb_event_base;
+
char *sink_name;
char *scache_item;
@@ -60,14 +68,7 @@ struct userdata {
pa_x11_client *x11_client;
};
-static const char* const valid_modargs[] = {
- "sink",
- "sample",
- "display",
- NULL
-};
-
-static int x11_event_callback(pa_x11_wrapper *w, XEvent *e, void *userdata) {
+static int x11_event_cb(pa_x11_wrapper *w, XEvent *e, void *userdata) {
XkbBellNotifyEvent *bne;
struct userdata *u = userdata;
@@ -89,6 +90,25 @@ static int x11_event_callback(pa_x11_wrapper *w, XEvent *e, void *userdata) {
return 1;
}
+static void x11_kill_cb(pa_x11_wrapper *w, void *userdata) {
+ struct userdata *u = userdata;
+
+ pa_assert(w);
+ pa_assert(u);
+ pa_assert(u->x11_wrapper == w);
+
+ if (u->x11_client)
+ pa_x11_client_free(u->x11_client);
+
+ if (u->x11_wrapper)
+ pa_x11_wrapper_unref(u->x11_wrapper);
+
+ u->x11_client = NULL;
+ u->x11_wrapper = NULL;
+
+ pa_module_unload_request(u->module);
+}
+
int pa__init(pa_module*m) {
struct userdata *u = NULL;
@@ -105,7 +125,8 @@ int pa__init(pa_module*m) {
m->userdata = u = pa_xnew(struct userdata, 1);
u->core = m->core;
- u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "x11-bell"));
+ u->module = m;
+ u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "bell-window-system"));
u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
u->x11_client = NULL;
@@ -133,7 +154,7 @@ int pa__init(pa_module*m) {
XkbSetAutoResetControls(pa_x11_wrapper_get_display(u->x11_wrapper), XkbAudibleBellMask, &auto_ctrls, &auto_values);
XkbChangeEnabledControls(pa_x11_wrapper_get_display(u->x11_wrapper), XkbUseCoreKbd, XkbAudibleBellMask, 0);
- u->x11_client = pa_x11_client_new(u->x11_wrapper, x11_event_callback, u);
+ u->x11_client = pa_x11_client_new(u->x11_wrapper, x11_event_cb, x11_kill_cb, u);
pa_modargs_free(ma);
@@ -153,11 +174,9 @@ void pa__done(pa_module*m) {
pa_assert(m);
- if (!m->userdata)
+ if (!(u = m->userdata))
return;
- u = m->userdata;
-
pa_xfree(u->scache_item);
pa_xfree(u->sink_name);
diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c
index 429c2a69..705d90f4 100644
--- a/src/modules/module-x11-publish.c
+++ b/src/modules/module-x11-publish.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -54,7 +52,7 @@
#include "module-x11-publish-symdef.h"
PA_MODULE_AUTHOR("Lennart Poettering");
-PA_MODULE_DESCRIPTION("X11 Credential Publisher");
+PA_MODULE_DESCRIPTION("X11 credential publisher");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE("display=<X11 display>");
@@ -69,16 +67,39 @@ static const char* const valid_modargs[] = {
struct userdata {
pa_core *core;
- pa_x11_wrapper *x11_wrapper;
+ pa_module *module;
+
char *id;
uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
- int auth_cookie_in_property;
+ pa_bool_t auth_cookie_in_property;
+
+ pa_x11_wrapper *x11_wrapper;
+ pa_x11_client *x11_client;
};
+static void x11_kill_cb(pa_x11_wrapper *w, void *userdata) {
+ struct userdata *u = userdata;
+
+ pa_assert(w);
+ pa_assert(u);
+ pa_assert(u->x11_wrapper == w);
+
+ if (u->x11_client)
+ pa_x11_client_free(u->x11_client);
+
+ if (u->x11_wrapper)
+ pa_x11_wrapper_unref(u->x11_wrapper);
+
+ u->x11_client = NULL;
+ u->x11_wrapper = NULL;
+
+ pa_module_unload_request(u->module);
+}
+
static int load_key(struct userdata *u, const char*fn) {
pa_assert(u);
- u->auth_cookie_in_property = 0;
+ u->auth_cookie_in_property = FALSE;
if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) {
pa_log_debug("using already loaded auth cookie.");
@@ -96,7 +117,7 @@ static int load_key(struct userdata *u, const char*fn) {
pa_log_debug("Loading cookie from disk.");
if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0)
- u->auth_cookie_in_property = 1;
+ u->auth_cookie_in_property = TRUE;
return 0;
}
@@ -117,10 +138,13 @@ int pa__init(pa_module*m) {
goto fail;
}
- m->userdata = u = pa_xmalloc(sizeof(struct userdata));
+ m->userdata = u = pa_xnew(struct userdata, 1);
u->core = m->core;
+ u->module = m;
u->id = NULL;
- u->auth_cookie_in_property = 0;
+ u->auth_cookie_in_property = FALSE;
+ u->x11_client = NULL;
+ u->x11_wrapper = NULL;
if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0)
goto fail;
@@ -152,7 +176,10 @@ int pa__init(pa_module*m) {
pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx)));
+ u->x11_client = pa_x11_client_new(u->x11_wrapper, NULL, x11_kill_cb, u);
+
pa_modargs_free(ma);
+
return 0;
fail:
@@ -160,6 +187,7 @@ fail:
pa_modargs_free(ma);
pa__done(m);
+
return -1;
}
@@ -171,6 +199,9 @@ void pa__done(pa_module*m) {
if (!(u = m->userdata))
return;
+ if (u->x11_client)
+ pa_x11_client_free(u->x11_client);
+
if (u->x11_wrapper) {
char t[256];
@@ -185,10 +216,9 @@ void pa__done(pa_module*m) {
pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_COOKIE");
XSync(pa_x11_wrapper_get_display(u->x11_wrapper), False);
}
- }
- if (u->x11_wrapper)
pa_x11_wrapper_unref(u->x11_wrapper);
+ }
if (u->auth_cookie_in_property)
pa_authkey_prop_unref(m->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
diff --git a/src/modules/module-x11-xsmp.c b/src/modules/module-x11-xsmp.c
index e9efa096..696826d8 100644
--- a/src/modules/module-x11-xsmp.c
+++ b/src/modules/module-x11-xsmp.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -42,6 +40,7 @@
#include <pulsecore/namereg.h>
#include <pulsecore/log.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/x11wrap.h>
#include "module-x11-xsmp-symdef.h"
@@ -49,20 +48,36 @@ PA_MODULE_AUTHOR("Lennart Poettering");
PA_MODULE_DESCRIPTION("X11 session management");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(TRUE);
+PA_MODULE_USAGE("session_manager=<session manager string> display=<X11 display>");
-static int ice_in_use = 0;
+static pa_bool_t ice_in_use = FALSE;
static const char* const valid_modargs[] = {
+ "session_manager",
+ "display",
NULL
};
+struct userdata {
+ pa_core *core;
+ pa_module *module;
+ pa_client *client;
+ SmcConn connection;
+ pa_x11_wrapper *x11;
+};
+
static void die_cb(SmcConn connection, SmPointer client_data){
- pa_core *c = PA_CORE(client_data);
+ struct userdata *u = client_data;
+ pa_assert(u);
+
+ pa_log_debug("Got die message from XSMP.");
- pa_log_debug("Got die message from XSM. Exiting...");
+ pa_x11_wrapper_kill(u->x11);
- pa_core_assert_ref(c);
- c->mainloop->quit(c->mainloop, 0);
+ pa_x11_wrapper_unref(u->x11);
+ u->x11 = NULL;
+
+ pa_module_unload_request(u->module);
}
static void save_complete_cb(SmcConn connection, SmPointer client_data) {
@@ -86,12 +101,15 @@ static void ice_io_cb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_fla
}
static void new_ice_connection(IceConn connection, IcePointer client_data, Bool opening, IcePointer *watch_data) {
- pa_core *c = client_data;
-
- pa_assert(c);
+ struct pa_core *c = client_data;
if (opening)
- *watch_data = c->mainloop->io_new(c->mainloop, IceConnectionNumber(connection), PA_IO_EVENT_INPUT, ice_io_cb, connection);
+ *watch_data = c->mainloop->io_new(
+ c->mainloop,
+ IceConnectionNumber(connection),
+ PA_IO_EVENT_INPUT,
+ ice_io_cb,
+ connection);
else
c->mainloop->io_free(*watch_data);
}
@@ -99,12 +117,13 @@ static void new_ice_connection(IceConn connection, IcePointer client_data, Bool
int pa__init(pa_module*m) {
pa_modargs *ma = NULL;
- char t[256], *vendor, *client_id;
+ char t[256], *vendor, *client_id, *k;
SmcCallbacks callbacks;
SmProp prop_program, prop_user;
SmProp *prop_list[2];
SmPropValue val_program, val_user;
- SmcConn connection;
+ struct userdata *u;
+ const char *e;
pa_assert(m);
@@ -114,21 +133,33 @@ int pa__init(pa_module*m) {
}
IceAddConnectionWatch(new_ice_connection, m->core);
- ice_in_use = 1;
+ ice_in_use = TRUE;
+
+ m->userdata = u = pa_xnew(struct userdata, 1);
+ u->core = m->core;
+ u->module = m;
+ u->client = NULL;
+ u->connection = NULL;
+ u->x11 = NULL;
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
pa_log("Failed to parse module arguments");
goto fail;
}
- if (!getenv("SESSION_MANAGER")) {
+ if (!(u->x11 = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL))))
+ goto fail;
+
+ e = pa_modargs_get_value(ma, "session_manager", NULL);
+
+ if (!e && !getenv("SESSION_MANAGER")) {
pa_log("X11 session manager not running.");
goto fail;
}
memset(&callbacks, 0, sizeof(callbacks));
callbacks.die.callback = die_cb;
- callbacks.die.client_data = m->core;
+ callbacks.die.client_data = u;
callbacks.save_yourself.callback = save_yourself_cb;
callbacks.save_yourself.client_data = m->core;
callbacks.save_complete.callback = save_complete_cb;
@@ -136,8 +167,8 @@ int pa__init(pa_module*m) {
callbacks.shutdown_cancelled.callback = shutdown_cancelled_cb;
callbacks.shutdown_cancelled.client_data = m->core;
- if (!(m->userdata = connection = SmcOpenConnection(
- NULL, m->core,
+ if (!(u->connection = SmcOpenConnection(
+ (char*) e, m->core,
SmProtoMajor, SmProtoMinor,
SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
&callbacks, NULL, &client_id,
@@ -164,9 +195,16 @@ int pa__init(pa_module*m) {
prop_user.vals = &val_user;
prop_list[1] = &prop_user;
- SmcSetProperties(connection, PA_ELEMENTSOF(prop_list), prop_list);
+ SmcSetProperties(u->connection, PA_ELEMENTSOF(prop_list), prop_list);
+
+ pa_log_info("Connected to session manager '%s' as '%s'.", vendor = SmcVendor(u->connection), client_id);
+ k = pa_sprintf_malloc("XSMP Session on %s as %s", vendor, client_id);
+ u->client = pa_client_new(u->core, __FILE__, k);
+ pa_xfree(k);
+
+ pa_proplist_sets(u->client->proplist, "xsmp.vendor", vendor);
+ pa_proplist_sets(u->client->proplist, "xsmp.client.id", client_id);
- pa_log_info("Connected to session manager '%s' as '%s'.", vendor = SmcVendor(connection), client_id);
free(vendor);
free(client_id);
@@ -184,13 +222,26 @@ fail:
}
void pa__done(pa_module*m) {
+ struct userdata *u;
+
pa_assert(m);
- if (m->userdata)
- SmcCloseConnection(m->userdata, 0, NULL);
+ if ((u = m->userdata)) {
+
+ if (u->connection)
+ SmcCloseConnection(u->connection, 0, NULL);
+
+ if (u->client)
+ pa_client_free(u->client);
+
+ if (u->x11)
+ pa_x11_wrapper_unref(u->x11);
+
+ pa_xfree(u);
+ }
if (ice_in_use) {
IceRemoveConnectionWatch(new_ice_connection, m->core);
- ice_in_use = 0;
+ ice_in_use = FALSE;
}
}
diff --git a/src/modules/module-zeroconf-discover.c b/src/modules/module-zeroconf-discover.c
index 4e76f448..2fc81370 100644
--- a/src/modules/module-zeroconf-discover.c
+++ b/src/modules/module-zeroconf-discover.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -164,8 +162,7 @@ static void resolver_cb(
pa_module *m;
ss = u->core->default_sample_spec;
- pa_assert_se(pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_AUX));
- pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT);
+ pa_channel_map_init_extend(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT);
for (l = txt; l; l = l->next) {
char *key, *value;
@@ -190,10 +187,8 @@ static void resolver_cb(
avahi_free(value);
}
- if (!channel_map_set && cm.channels != ss.channels) {
- pa_assert_se(pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_AUX));
- pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT);
- }
+ if (!channel_map_set && cm.channels != ss.channels)
+ pa_channel_map_init_extend(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT);
if (!pa_sample_spec_valid(&ss)) {
pa_log("Service '%s' contains an invalid sample specification.", name);
@@ -237,7 +232,7 @@ static void resolver_cb(
t, dname,
pa_channel_map_snprint(cmt, sizeof(cmt), &cm));
- pa_log_debug("Loading module-tunnel-%s with arguments '%s'", module_name, args);
+ pa_log_debug("Loading %s with arguments '%s'", module_name, args);
if ((m = pa_module_load(u->core, module_name, args))) {
tnl->module_index = m->index;
diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c
index 6ed8e3d9..cb9c1285 100644
--- a/src/modules/module-zeroconf-publish.c
+++ b/src/modules/module-zeroconf-publish.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -578,12 +576,12 @@ int pa__init(pa_module*m) {
u->services = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
- u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], (pa_hook_cb_t) device_new_or_changed_cb, u);
- u->sink_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], (pa_hook_cb_t) device_new_or_changed_cb, u);
- u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) device_unlink_cb, u);
- u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], (pa_hook_cb_t) device_new_or_changed_cb, u);
- u->source_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], (pa_hook_cb_t) device_new_or_changed_cb, u);
- u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], (pa_hook_cb_t) device_unlink_cb, u);
+ u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u);
+ u->sink_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u);
+ u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) device_unlink_cb, u);
+ u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u);
+ u->source_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u);
+ u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) device_unlink_cb, u);
u->main_entry_group = NULL;
diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c
index e29f0eda..2791e165 100644
--- a/src/modules/oss-util.c
+++ b/src/modules/oss-util.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/oss-util.h b/src/modules/oss-util.h
index 8fea805c..654f7bba 100644
--- a/src/modules/oss-util.h
+++ b/src/modules/oss-util.h
@@ -1,8 +1,6 @@
#ifndef fooossutilhfoo
#define fooossutilhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c
index 3a526c14..d0d06c4d 100644
--- a/src/modules/rtp/module-rtp-send.c
+++ b/src/modules/rtp/module-rtp-send.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c
index 5c299844..5a33ebc2 100644
--- a/src/modules/rtp/rtp.c
+++ b/src/modules/rtp/rtp.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/rtp/rtp.h b/src/modules/rtp/rtp.h
index a366d7a6..a2728f05 100644
--- a/src/modules/rtp/rtp.h
+++ b/src/modules/rtp/rtp.h
@@ -1,8 +1,6 @@
#ifndef foortphfoo
#define foortphfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c
index 123bc494..5d9b58fa 100644
--- a/src/modules/rtp/sap.c
+++ b/src/modules/rtp/sap.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/rtp/sap.h b/src/modules/rtp/sap.h
index db096d61..69c757cb 100644
--- a/src/modules/rtp/sap.h
+++ b/src/modules/rtp/sap.h
@@ -1,8 +1,6 @@
#ifndef foosaphfoo
#define foosaphfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c
index 9265a200..cef90433 100644
--- a/src/modules/rtp/sdp.c
+++ b/src/modules/rtp/sdp.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/modules/rtp/sdp.h b/src/modules/rtp/sdp.h
index 7c91fca6..933a602b 100644
--- a/src/modules/rtp/sdp.h
+++ b/src/modules/rtp/sdp.h
@@ -1,8 +1,6 @@
#ifndef foosdphfoo
#define foosdphfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/.gitignore b/src/pulse/.gitignore
new file mode 100644
index 00000000..67020331
--- /dev/null
+++ b/src/pulse/.gitignore
@@ -0,0 +1 @@
+version.h
diff --git a/src/pulse/browser.c b/src/pulse/browser.c
index 5e4aa87b..1a3f657f 100644
--- a/src/pulse/browser.c
+++ b/src/pulse/browser.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/browser.h b/src/pulse/browser.h
index b039ca33..c4e0a17e 100644
--- a/src/pulse/browser.h
+++ b/src/pulse/browser.h
@@ -1,8 +1,6 @@
#ifndef foobrowserhfoo
#define foobrowserhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/cdecl.h b/src/pulse/cdecl.h
index 922ad276..8c5b2d0f 100644
--- a/src/pulse/cdecl.h
+++ b/src/pulse/cdecl.h
@@ -1,8 +1,6 @@
#ifndef foopulsecdeclhfoo
#define foopulsecdeclhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c
index 2b35ee75..7348b32e 100644
--- a/src/pulse/channelmap.c
+++ b/src/pulse/channelmap.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -396,6 +394,34 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p
}
}
+pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) {
+ unsigned c;
+
+ pa_assert(m);
+ pa_assert(channels > 0);
+ pa_assert(channels <= PA_CHANNELS_MAX);
+
+ pa_channel_map_init(m);
+
+ for (c = channels; c > 0; c--) {
+
+ if (pa_channel_map_init_auto(m, c, def)) {
+ unsigned i = 0;
+
+ for (; c < channels; c++) {
+
+ m->map[c] = PA_CHANNEL_POSITION_AUX0 + i;
+ i++;
+ }
+
+ m->channels = channels;
+
+ return m;
+ }
+ }
+
+ return NULL;
+}
const char* pa_channel_position_to_string(pa_channel_position_t pos) {
diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h
index 00d3eb0d..2551eae9 100644
--- a/src/pulse/channelmap.h
+++ b/src/pulse/channelmap.h
@@ -1,8 +1,6 @@
#ifndef foochannelmaphfoo
#define foochannelmaphfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -168,10 +166,18 @@ pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m);
/** Initialize the specified channel map for stereophonic audio and return a pointer to it */
pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m);
-/** Initialize the specified channel map for the specified number
- * of channels using default labels and return a pointer to it. */
+/** Initialize the specified channel map for the specified number of
+ * channels using default labels and return a pointer to it. This call
+ * will fail (return NULL) if there is no default channel map known for this
+ * specific number of channels and mapping. */
pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def);
+/** Similar to pa_channel_map_init_auto() but instead of failing if no
+ * default mapping is known with the specified parameters it will
+ * synthesize a mapping based on a known mapping with fewer channels
+ * and fill up the rest with AUX0...AUX31 channels \since 0.9.11 */
+pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def);
+
/** Return a text label for the specified channel position */
const char* pa_channel_position_to_string(pa_channel_position_t pos) PA_GCC_PURE;
diff --git a/src/pulse/client-conf-x11.c b/src/pulse/client-conf-x11.c
index 49df4b6c..393a7cd3 100644
--- a/src/pulse/client-conf-x11.c
+++ b/src/pulse/client-conf-x11.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/client-conf-x11.h b/src/pulse/client-conf-x11.h
index 56cd406d..f2f40e03 100644
--- a/src/pulse/client-conf-x11.h
+++ b/src/pulse/client-conf-x11.h
@@ -1,8 +1,6 @@
#ifndef fooclientconfx11hfoo
#define fooclientconfx11hfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c
index 75f44182..2ead871f 100644
--- a/src/pulse/client-conf.c
+++ b/src/pulse/client-conf.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -58,7 +56,7 @@ static const pa_client_conf default_conf = {
.default_sink = NULL,
.default_source = NULL,
.default_server = NULL,
- .autospawn = FALSE,
+ .autospawn = TRUE,
.disable_shm = FALSE,
.cookie_file = NULL,
.cookie_valid = FALSE,
@@ -178,11 +176,11 @@ int pa_client_conf_env(pa_client_conf *c) {
int pa_client_conf_load_cookie(pa_client_conf* c) {
pa_assert(c);
- c->cookie_valid = FALSE;
-
if (!c->cookie_file)
return -1;
+ c->cookie_valid = FALSE;
+
if (pa_authkey_load_auto(c->cookie_file, c->cookie, sizeof(c->cookie)) < 0)
return -1;
diff --git a/src/pulse/client-conf.h b/src/pulse/client-conf.h
index 7cc975e6..699279aa 100644
--- a/src/pulse/client-conf.h
+++ b/src/pulse/client-conf.h
@@ -1,8 +1,6 @@
#ifndef fooclientconfhfoo
#define fooclientconfhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/client.conf.in b/src/pulse/client.conf.in
index 2bc8a7c8..749e9688 100644
--- a/src/pulse/client.conf.in
+++ b/src/pulse/client.conf.in
@@ -1,5 +1,3 @@
-# $Id$
-#
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
@@ -25,7 +23,7 @@
; default-source =
; default-server =
-; autospawn = no
+; autospawn = yes
; daemon-binary = @PA_BINARY@
; extra-arguments = --log-target=syslog --exit-idle-time=5
diff --git a/src/pulse/context.c b/src/pulse/context.c
index f9f021af..f56cb241 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -70,6 +68,7 @@
#include <pulsecore/socket-util.h>
#include <pulsecore/creds.h>
#include <pulsecore/macro.h>
+#include <pulsecore/proplist-util.h>
#include "internal.h"
@@ -103,7 +102,9 @@ static void unlock_autospawn_lock_file(pa_context *c) {
if (c->autospawn_lock_fd >= 0) {
char *lf;
- lf = pa_runtime_path(AUTOSPAWN_LOCK);
+ if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK)))
+ pa_log_warn("Cannot unlock autospawn because runtime path is no more.");
+
pa_unlock_lockfile(lf, c->autospawn_lock_fd);
pa_xfree(lf);
@@ -167,6 +168,7 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
c->autospawn_lock_fd = -1;
memset(&c->spawn_api, 0, sizeof(c->spawn_api));
c->do_autospawn = FALSE;
+ c->do_shm = FALSE;
#ifndef MSG_NOSIGNAL
#ifdef SIGPIPE
@@ -175,10 +177,10 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
#endif
c->conf = pa_client_conf_new();
- pa_client_conf_load(c->conf, NULL);
#ifdef HAVE_X11
pa_client_conf_from_x11(c->conf, NULL);
#endif
+ pa_client_conf_load(c->conf, NULL);
pa_client_conf_env(c->conf);
if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm))) {
@@ -422,6 +424,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
switch(c->state) {
case PA_CONTEXT_AUTHORIZING: {
pa_tagstruct *reply;
+ pa_bool_t shm_on_remote;
if (pa_tagstruct_getu32(t, &c->version) < 0 ||
!pa_tagstruct_eof(t)) {
@@ -435,10 +438,22 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
goto finish;
}
+ /* Starting with protocol version 13 the MSB of the version
+ tag reflects if shm is available for this connection or
+ not. */
+ if (c->version >= 13) {
+ shm_on_remote = !!(c->version & 0x80000000U);
+ c->version &= 0x7FFFFFFFU;
+ }
+
+ pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
+
/* Enable shared memory support if possible */
- if (c->version >= 10 &&
- pa_mempool_is_shared(c->mempool) &&
- c->is_local) {
+ if (c->do_shm)
+ if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
+ c->do_shm = FALSE;
+
+ if (c->do_shm) {
/* Only enable SHM if both sides are owned by the same
* user. This is a security measure because otherwise
@@ -446,12 +461,14 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
#ifdef HAVE_CREDS
const pa_creds *creds;
- if ((creds = pa_pdispatch_creds(pd)))
- if (getuid() == creds->uid)
- pa_pstream_enable_shm(c->pstream, TRUE);
+ if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
+ c->do_shm = FALSE;
#endif
}
+ pa_log_debug("Negotiated SHM: %s", pa_yes_no(c->do_shm));
+ pa_pstream_enable_shm(c->pstream, c->do_shm);
+
reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
if (c->version >= 13) {
@@ -510,7 +527,16 @@ static void setup_context(pa_context *c, pa_iochannel *io) {
pa_log_info("No cookie loaded. Attempting to connect without.");
t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag);
- pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION);
+
+ c->do_shm =
+ pa_mempool_is_shared(c->mempool) &&
+ c->is_local;
+
+ pa_log_debug("SHM possible: %s", pa_yes_no(c->do_shm));
+
+ /* Starting with protocol version 13 we use the MSB of the version
+ * tag for informing the other side if we could do SHM or not */
+ pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION | (c->do_shm ? 0x80000000U : 0));
pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie));
#ifdef HAVE_CREDS
@@ -621,6 +647,7 @@ static int context_connect_spawn(pa_context *c) {
/* Parent */
pa_assert_se(pa_close(fds[1]) == 0);
+ fds[1] = -1;
r = waitpid(pid, &status, 0);
@@ -749,11 +776,15 @@ static char *get_legacy_runtime_dir(void) {
p = pa_sprintf_malloc("/tmp/pulse-%s", u);
- if (stat(p, &st) < 0)
+ if (stat(p, &st) < 0) {
+ pa_xfree(p);
return NULL;
+ }
- if (st.st_uid != getuid())
+ if (st.st_uid != getuid()) {
+ pa_xfree(p);
return NULL;
+ }
return p;
}
@@ -809,7 +840,7 @@ int pa_context_connect(
/* The system wide instance */
c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
- /* The old per-user instance path. This is supported only to easy upgrades */
+ /* The old per-user instance path. This is supported only to ease upgrades */
if ((legacy_dir = get_legacy_runtime_dir())) {
char *p = pa_sprintf_malloc("%s" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, legacy_dir);
c->server_list = pa_strlist_prepend(c->server_list, p);
@@ -818,14 +849,20 @@ int pa_context_connect(
}
/* The per-user instance */
- c->server_list = pa_strlist_prepend(c->server_list, ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET));
- pa_xfree(ufn);
+ if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) {
+ c->server_list = pa_strlist_prepend(c->server_list, ufn);
+ pa_xfree(ufn);
+ }
/* Wrap the connection attempts in a single transaction for sane autospawn locking */
if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
char *lf;
- lf = pa_runtime_path(AUTOSPAWN_LOCK);
+ if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) {
+ pa_context_fail(c, PA_ERR_ACCESS);
+ goto finish;
+ }
+
pa_assert(c->autospawn_lock_fd <= 0);
c->autospawn_lock_fd = pa_lock_lockfile(lf);
pa_xfree(lf);
@@ -1193,85 +1230,3 @@ pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[]
return o;
}
-
-void pa_init_proplist(pa_proplist *p) {
- int a, b;
-#ifndef HAVE_DECL_ENVIRON
- extern char **environ;
-#endif
- char **e;
-
- pa_assert(p);
-
- for (e = environ; *e; e++) {
-
- if (pa_startswith(*e, "PULSE_PROP_")) {
- size_t kl = strcspn(*e+11, "=");
- char *k;
-
- if ((*e)[11+kl] != '=')
- continue;
-
- if (!pa_utf8_valid(*e+11+kl+1))
- continue;
-
- k = pa_xstrndup(*e+11, kl);
-
- if (pa_proplist_contains(p, k)) {
- pa_xfree(k);
- continue;
- }
-
- pa_proplist_sets(p, k, *e+11+kl+1);
- pa_xfree(k);
- }
- }
-
- if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_ID)) {
- char t[32];
- pa_snprintf(t, sizeof(t), "%lu", (unsigned long) getpid());
- pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_ID, t);
- }
-
- if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_USER)) {
- char t[64];
- if (pa_get_user_name(t, sizeof(t))) {
- char *c = pa_utf8_filter(t);
- pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_USER, c);
- pa_xfree(c);
- }
- }
-
- if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_HOST)) {
- char t[64];
- if (pa_get_host_name(t, sizeof(t))) {
- char *c = pa_utf8_filter(t);
- pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_HOST, c);
- pa_xfree(c);
- }
- }
-
- a = pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_BINARY);
- b = pa_proplist_contains(p, PA_PROP_APPLICATION_NAME);
-
- if (!a || !b) {
- char t[PATH_MAX];
- if (pa_get_binary_name(t, sizeof(t))) {
- char *c = pa_utf8_filter(t);
-
- if (!a)
- pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_BINARY, c);
- if (!b)
- pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, c);
-
- pa_xfree(c);
- }
- }
-
- if (!pa_proplist_contains(p, PA_PROP_APPLICATION_LANGUAGE)) {
- const char *l;
-
- if ((l = setlocale(LC_MESSAGES, NULL)))
- pa_proplist_sets(p, PA_PROP_APPLICATION_LANGUAGE, l);
- }
-}
diff --git a/src/pulse/context.h b/src/pulse/context.h
index 143508f4..8dff7642 100644
--- a/src/pulse/context.h
+++ b/src/pulse/context.h
@@ -1,8 +1,6 @@
#ifndef foocontexthfoo
#define foocontexthfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/def.h b/src/pulse/def.h
index 10722329..a91c1031 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -1,8 +1,6 @@
#ifndef foodefhfoo
#define foodefhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/error.c b/src/pulse/error.c
index 78f0da95..29690c89 100644
--- a/src/pulse/error.c
+++ b/src/pulse/error.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/error.h b/src/pulse/error.h
index 44a2e5ec..9f9e3d33 100644
--- a/src/pulse/error.h
+++ b/src/pulse/error.h
@@ -1,8 +1,6 @@
#ifndef fooerrorhfoo
#define fooerrorhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/gccmacro.h b/src/pulse/gccmacro.h
index 032c3bae..e4062033 100644
--- a/src/pulse/gccmacro.h
+++ b/src/pulse/gccmacro.h
@@ -1,8 +1,6 @@
#ifndef foopulsegccmacrohfoo
#define foopulsegccmacrohfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/glib-mainloop.c b/src/pulse/glib-mainloop.c
index b7a7537a..6ddb0faa 100644
--- a/src/pulse/glib-mainloop.c
+++ b/src/pulse/glib-mainloop.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/glib-mainloop.h b/src/pulse/glib-mainloop.h
index a4e06ea0..60fd61a3 100644
--- a/src/pulse/glib-mainloop.h
+++ b/src/pulse/glib-mainloop.h
@@ -1,8 +1,6 @@
#ifndef fooglibmainloophfoo
#define fooglibmainloophfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/internal.h b/src/pulse/internal.h
index d346e945..9ed541d1 100644
--- a/src/pulse/internal.h
+++ b/src/pulse/internal.h
@@ -1,8 +1,6 @@
#ifndef foointernalhfoo
#define foointernalhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -75,8 +73,9 @@ struct pa_context {
pa_mempool *mempool;
- pa_bool_t is_local;
- pa_bool_t do_autospawn;
+ pa_bool_t is_local:1;
+ pa_bool_t do_autospawn:1;
+ pa_bool_t do_shm:1;
int autospawn_lock_fd;
pa_spawn_api spawn_api;
@@ -106,6 +105,8 @@ struct pa_stream {
pa_context *context;
pa_mainloop_api *mainloop;
+ uint32_t direct_on_input;
+
pa_stream_direction_t direction;
pa_stream_state_t state;
pa_stream_flags_t flags;
@@ -115,8 +116,13 @@ struct pa_stream {
pa_proplist *proplist;
+ pa_bool_t channel_valid:1;
+ pa_bool_t suspended:1;
+ pa_bool_t corked:1;
+ pa_bool_t timing_info_valid:1;
+ pa_bool_t auto_timing_update_requested:1;
+
uint32_t channel;
- pa_bool_t channel_valid;
uint32_t syncid;
uint32_t stream_index;
@@ -125,17 +131,13 @@ struct pa_stream {
uint32_t device_index;
char *device_name;
- pa_bool_t suspended;
pa_memchunk peek_memchunk;
void *peek_data;
pa_memblockq *record_memblockq;
- pa_bool_t corked;
-
/* Store latest latency info */
pa_timing_info timing_info;
- pa_bool_t timing_info_valid;
/* Use to make sure that time advances monotonically */
pa_usec_t previous_time;
@@ -150,7 +152,6 @@ struct pa_stream {
/* Latency interpolation stuff */
pa_time_event *auto_timing_update_event;
- pa_bool_t auto_timing_update_requested;
pa_smoother *smoother;
@@ -232,6 +233,4 @@ pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *ta
#define PA_CHECK_VALIDITY_RETURN_NULL(context, expression, error) PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, NULL)
-void pa_init_proplist(pa_proplist *p);
-
#endif
diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
index 857e82b4..4be2c62a 100644
--- a/src/pulse/introspect.c
+++ b/src/pulse/introspect.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -106,7 +104,8 @@ static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command,
pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
pa_tagstruct_gets(t, &i.default_sink_name) < 0 ||
pa_tagstruct_gets(t, &i.default_source_name) < 0 ||
- pa_tagstruct_getu32(t, &i.cookie) < 0) {
+ pa_tagstruct_getu32(t, &i.cookie) < 0 ||
+ !pa_tagstruct_eof(t)) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
goto finish;
@@ -1342,7 +1341,7 @@ pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, p
return o;
}
-pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, char *sink_name, pa_context_success_cb_t cb, void* userdata) {
+pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, const char *sink_name, pa_context_success_cb_t cb, void* userdata) {
pa_operation *o;
pa_tagstruct *t;
uint32_t tag;
@@ -1392,7 +1391,7 @@ pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, u
return o;
}
-pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, char *source_name, pa_context_success_cb_t cb, void* userdata) {
+pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, const char *source_name, pa_context_success_cb_t cb, void* userdata) {
pa_operation *o;
pa_tagstruct *t;
uint32_t tag;
@@ -1442,7 +1441,7 @@ pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx
return o;
}
-pa_operation* pa_context_suspend_sink_by_name(pa_context *c, char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata) {
+pa_operation* pa_context_suspend_sink_by_name(pa_context *c, const char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata) {
pa_operation *o;
pa_tagstruct *t;
uint32_t tag;
@@ -1489,7 +1488,7 @@ pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int
return o;
}
-pa_operation* pa_context_suspend_source_by_name(pa_context *c, char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata) {
+pa_operation* pa_context_suspend_source_by_name(pa_context *c, const char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata) {
pa_operation *o;
pa_tagstruct *t;
uint32_t tag;
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index d185a3a6..c8c13a75 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -1,8 +1,6 @@
#ifndef foointrospecthfoo
#define foointrospecthfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -261,7 +259,7 @@ pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int
pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata);
/** Suspend/Resume a sink. \since 0.9.7 */
-pa_operation* pa_context_suspend_sink_by_name(pa_context *c, char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata);
+pa_operation* pa_context_suspend_sink_by_name(pa_context *c, const char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata);
/** Suspend/Resume a sink. If idx is PA_INVALID_INDEX all sinks will be suspended. \since 0.9.7 */
pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata);
@@ -433,7 +431,7 @@ pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sin
pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata);
/** Move the specified sink input to a different sink. \since 0.9.5 */
-pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, char *sink_name, pa_context_success_cb_t cb, void* userdata);
+pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, const char *sink_name, pa_context_success_cb_t cb, void* userdata);
/** Move the specified sink input to a different sink. \since 0.9.5 */
pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, uint32_t sink_idx, pa_context_success_cb_t cb, void* userdata);
@@ -479,13 +477,13 @@ pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_
pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata);
/** Move the specified source output to a different source. \since 0.9.5 */
-pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, char *source_name, pa_context_success_cb_t cb, void* userdata);
+pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, const char *source_name, pa_context_success_cb_t cb, void* userdata);
/** Move the specified source output to a different source. \since 0.9.5 */
pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata);
/** Suspend/Resume a source. \since 0.9.7 */
-pa_operation* pa_context_suspend_source_by_name(pa_context *c, char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata);
+pa_operation* pa_context_suspend_source_by_name(pa_context *c, const char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata);
/** Suspend/Resume a source. If idx is PA_INVALID_INDEX all sources will be suspended. \since 0.9.7 */
pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata);
diff --git a/src/pulse/mainloop-api.c b/src/pulse/mainloop-api.c
index dda51297..90aff164 100644
--- a/src/pulse/mainloop-api.c
+++ b/src/pulse/mainloop-api.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/mainloop-api.h b/src/pulse/mainloop-api.h
index 985806e6..53c7411e 100644
--- a/src/pulse/mainloop-api.h
+++ b/src/pulse/mainloop-api.h
@@ -1,8 +1,6 @@
#ifndef foomainloopapihfoo
#define foomainloopapihfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/mainloop-signal.c b/src/pulse/mainloop-signal.c
index 91c6bf6d..9161dec4 100644
--- a/src/pulse/mainloop-signal.c
+++ b/src/pulse/mainloop-signal.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/mainloop-signal.h b/src/pulse/mainloop-signal.h
index bdb0f738..a6c16f2f 100644
--- a/src/pulse/mainloop-signal.h
+++ b/src/pulse/mainloop-signal.h
@@ -1,8 +1,6 @@
#ifndef foomainloopsignalhfoo
#define foomainloopsignalhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c
index ad4e4e97..aaed3caf 100644
--- a/src/pulse/mainloop.c
+++ b/src/pulse/mainloop.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/mainloop.h b/src/pulse/mainloop.h
index db2797fb..907e94a7 100644
--- a/src/pulse/mainloop.h
+++ b/src/pulse/mainloop.h
@@ -1,8 +1,6 @@
#ifndef foomainloophfoo
#define foomainloophfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/operation.c b/src/pulse/operation.c
index 6b5c142a..13b470a8 100644
--- a/src/pulse/operation.c
+++ b/src/pulse/operation.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/operation.h b/src/pulse/operation.h
index 97d1c6b8..188e2cb9 100644
--- a/src/pulse/operation.h
+++ b/src/pulse/operation.h
@@ -1,8 +1,6 @@
#ifndef foooperationhfoo
#define foooperationhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/proplist.c b/src/pulse/proplist.c
index 33bd274f..74aea20a 100644
--- a/src/pulse/proplist.c
+++ b/src/pulse/proplist.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index f433ec62..f75cca54 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -1,8 +1,6 @@
#ifndef foopulseproplisthfoo
#define foopulseproplisthfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -24,6 +22,8 @@
USA.
***/
+#include <sys/types.h>
+
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
@@ -40,16 +40,25 @@ PA_C_DECL_BEGIN
* media.icon_name
* media.role video, music, game, event, phone, production, filter, abstract, stream
* event.id button-click, session-login
- * event.x11.display
- * event.x11.xid
- * event.x11.x_pointer
- * event.x11.y_pointer
- * event.x11.button
+ * event.mouse.x
+ * event.mouse.y
+ * event.mouse.hpos
+ * event.mouse.vpos
+ * event.mouse.button
+ * window.name
+ * window.id
+ * window.icon
+ * window.icon_name
+ * window.x11.display
+ * window.x11.screen
+ * window.x11.monitor
+ * window.x11.xid
* application.name "Rhythmbox Media Player"
* application.id "org.gnome.rhythmbox"
* application.version
* application.icon
* application.icon_name
+ * application.language
* application.process.id
* application.process.binary
* application.process.user
@@ -60,14 +69,14 @@ PA_C_DECL_BEGIN
* device.bus_path
* device.serial
* device.vendor_product_id
- * device.class sound, modem, monitor, filter
+ * device.class sound, modem, monitor, filter, abstract
* device.form_factor laptop-speakers, external-speakers, telephone, tv-capture, webcam-capture, microphone-capture, headset
* device.connector isa, pci, usb, firewire, bluetooth
* device.access_mode mmap, mmap_rewrite, serial
* device.master_device
- * device.buffer_size
+ * device.bufferin.buffer_size
+ * device.bufferin.fragment_size
*/
-
#define PA_PROP_MEDIA_NAME "media.name"
#define PA_PROP_MEDIA_TITLE "media.title"
#define PA_PROP_MEDIA_ARTIST "media.artist"
@@ -77,11 +86,19 @@ PA_C_DECL_BEGIN
#define PA_PROP_MEDIA_ICON_NAME "media.icon_name"
#define PA_PROP_MEDIA_ROLE "media.role"
#define PA_PROP_EVENT_ID "event.id"
-#define PA_PROP_EVENT_X11_DISPLAY "event.x11.display"
-#define PA_PROP_EVENT_X11_XID "event.x11.xid"
#define PA_PROP_EVENT_MOUSE_X "event.mouse.x"
#define PA_PROP_EVENT_MOUSE_Y "event.mouse.y"
+#define PA_PROP_EVENT_MOUSE_HPOS "event.mouse.hpos"
+#define PA_PROP_EVENT_MOUSE_VPOS "event.mouse.vpos"
#define PA_PROP_EVENT_MOUSE_BUTTON "event.mouse.button"
+#define PA_PROP_WINDOW_NAME "window.name"
+#define PA_PROP_WINDOW_ID "window.id"
+#define PA_PROP_WINDOW_ICON "window.icon"
+#define PA_PROP_WINDOW_ICON_NAME "window.icon_name"
+#define PA_PROP_WINDOW_X11_DISPLAY "window.x11.display"
+#define PA_PROP_WINDOW_X11_SCREEN "window.x11.screen"
+#define PA_PROP_WINDOW_X11_MONITOR "window.x11.monitor"
+#define PA_PROP_WINDOW_X11_XID "window.x11.xid"
#define PA_PROP_APPLICATION_NAME "application.name"
#define PA_PROP_APPLICATION_ID "application.id"
#define PA_PROP_APPLICATION_VERSION "application.version"
@@ -174,9 +191,10 @@ int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]);
* to this variable should then be passed to pa_proplist_iterate()
* which should be called in a loop until it returns NULL which
* signifies EOL. The property list should not be modified during
- * iteration through the list. On each invication this function will
- * return the key string for the next entry. The keys in the property
- * list do not have any particular order. \since 0.9.11 */
+ * iteration through the list -- except for deleting the current
+ * looked at entry. On each invication this function will return the
+ * key string for the next entry. The keys in the property list do not
+ * have any particular order. \since 0.9.11 */
const char *pa_proplist_iterate(pa_proplist *p, void **state);
/** Format the property list nicely as a human readable string. Call pa_xfree() on the result. \since
diff --git a/src/pulse/pulseaudio.h b/src/pulse/pulseaudio.h
index 88d1275b..ee8a4bb8 100644
--- a/src/pulse/pulseaudio.h
+++ b/src/pulse/pulseaudio.h
@@ -1,8 +1,6 @@
#ifndef foopulseaudiohfoo
#define foopulseaudiohfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/sample.c b/src/pulse/sample.c
index 43340f20..4aef5bb0 100644
--- a/src/pulse/sample.c
+++ b/src/pulse/sample.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/sample.h b/src/pulse/sample.h
index dedd72de..1ba3f871 100644
--- a/src/pulse/sample.h
+++ b/src/pulse/sample.h
@@ -1,8 +1,6 @@
#ifndef foosamplehfoo
#define foosamplehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -115,10 +113,10 @@ PA_C_DECL_BEGIN
#endif
/** Maximum number of allowed channels */
-#define PA_CHANNELS_MAX 32
+#define PA_CHANNELS_MAX 32U
/** Maximum allowed sample rate */
-#define PA_RATE_MAX (48000*4)
+#define PA_RATE_MAX (48000U*4U)
/** Sample format */
typedef enum pa_sample_format {
diff --git a/src/pulse/scache.c b/src/pulse/scache.c
index e43a0b9f..5e31e7af 100644
--- a/src/pulse/scache.c
+++ b/src/pulse/scache.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -29,8 +27,11 @@
#include <stdio.h>
#include <string.h>
+#include <pulse/utf8.h>
+
#include <pulsecore/pstream-util.h>
#include <pulsecore/macro.h>
+#include <pulsecore/proplist-util.h>
#include "internal.h"
@@ -39,6 +40,7 @@
int pa_stream_connect_upload(pa_stream *s, size_t length) {
pa_tagstruct *t;
uint32_t tag;
+ const char *name;
pa_assert(s);
pa_assert(PA_REFCNT_VALUE(s) >= 1);
@@ -46,6 +48,11 @@ int pa_stream_connect_upload(pa_stream *s, size_t length) {
PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
PA_CHECK_VALIDITY(s->context, length > 0, PA_ERR_INVALID);
+ if (!(name = pa_proplist_gets(s->proplist, PA_PROP_EVENT_ID)))
+ name = pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME);
+
+ PA_CHECK_VALIDITY(s->context, name && *name && pa_utf8_valid(name), PA_ERR_INVALID);
+
pa_stream_ref(s);
s->direction = PA_STREAM_UPLOAD;
@@ -53,9 +60,7 @@ int pa_stream_connect_upload(pa_stream *s, size_t length) {
t = pa_tagstruct_command(s->context, PA_COMMAND_CREATE_UPLOAD_STREAM, &tag);
- if (s->context->version < 13)
- pa_tagstruct_puts(t, pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME));
-
+ pa_tagstruct_puts(t, name);
pa_tagstruct_put_sample_spec(t, &s->sample_spec);
pa_tagstruct_put_channel_map(t, &s->channel_map);
pa_tagstruct_putu32(t, length);
diff --git a/src/pulse/scache.h b/src/pulse/scache.h
index 46d86a19..f380b4e8 100644
--- a/src/pulse/scache.h
+++ b/src/pulse/scache.h
@@ -1,8 +1,6 @@
#ifndef fooscachehfoo
#define fooscachehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/simple.c b/src/pulse/simple.c
index 1072fb4d..70396835 100644
--- a/src/pulse/simple.c
+++ b/src/pulse/simple.c
@@ -1,6 +1,4 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/simple.h b/src/pulse/simple.h
index 7fca6ac3..a1380a0a 100644
--- a/src/pulse/simple.h
+++ b/src/pulse/simple.h
@@ -1,8 +1,6 @@
#ifndef foosimplehfoo
#define foosimplehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index 4268fd6f..3bee7a05 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -107,6 +105,8 @@ pa_stream *pa_stream_new_with_proplist(
s->sample_spec = *ss;
s->channel_map = *map;
+ s->direct_on_input = PA_INVALID_INDEX;
+
s->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();
if (name)
pa_proplist_sets(s->proplist, PA_PROP_MEDIA_NAME, name);
@@ -475,6 +475,8 @@ void pa_command_stream_suspended(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUS
if (s->suspended || s->corked)
pa_smoother_pause(s->smoother, x);
+ else
+ pa_smoother_resume(s->smoother, x);
}
request_auto_timing_update(s, TRUE);
@@ -625,7 +627,7 @@ static void invalidate_indexes(pa_stream *s, pa_bool_t r, pa_bool_t w) {
s->write_index_not_before = s->context->ctag;
if (s->timing_info_valid)
- s->timing_info.write_index_corrupt = 1;
+ s->timing_info.write_index_corrupt = TRUE;
/* pa_log("write_index invalidated"); */
}
@@ -634,7 +636,7 @@ static void invalidate_indexes(pa_stream *s, pa_bool_t r, pa_bool_t w) {
s->read_index_not_before = s->context->ctag;
if (s->timing_info_valid)
- s->timing_info.read_index_corrupt = 1;
+ s->timing_info.read_index_corrupt = TRUE;
/* pa_log("read_index invalidated"); */
}
@@ -838,6 +840,7 @@ static int create_stream(
pa_assert(direction == PA_STREAM_PLAYBACK || direction == PA_STREAM_RECORD);
PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
+ PA_CHECK_VALIDITY(s->context, s->direct_on_input == PA_INVALID_INDEX || direction == PA_STREAM_RECORD, PA_ERR_BADSTATE);
PA_CHECK_VALIDITY(s->context, !(flags & ~(PA_STREAM_START_CORKED|
PA_STREAM_INTERPOLATE_TIMING|
PA_STREAM_NOT_MONOTONOUS|
@@ -860,8 +863,8 @@ static int create_stream(
* when they are passed but actually not supported. This makes
* client development easier */
- PA_CHECK_VALIDITY(s->context, direction != PA_STREAM_PLAYBACK || !(flags & (PA_STREAM_START_MUTED)), PA_ERR_INVALID);
- PA_CHECK_VALIDITY(s->context, direction != PA_STREAM_RECORD || !(flags & (PA_STREAM_PEAK_DETECT)), PA_ERR_INVALID);
+ PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_PLAYBACK || !(flags & (PA_STREAM_START_MUTED)), PA_ERR_INVALID);
+ PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_RECORD || !(flags & (PA_STREAM_PEAK_DETECT)), PA_ERR_INVALID);
PA_CHECK_VALIDITY(s->context, !volume || volume->channels == s->sample_spec.channels, PA_ERR_INVALID);
PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID);
@@ -954,6 +957,9 @@ static int create_stream(
PA_TAG_BOOLEAN, flags & PA_STREAM_ADJUST_LATENCY,
PA_TAG_PROPLIST, s->proplist,
PA_TAG_INVALID);
+
+ if (s->direction == PA_STREAM_RECORD)
+ pa_tagstruct_putu32(t, s->direct_on_input);
}
pa_pstream_send_tagstruct(s->context->pstream, t);
@@ -2227,3 +2233,26 @@ pa_operation *pa_stream_proplist_remove(pa_stream *s, const char *const keys[],
return o;
}
+
+int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx) {
+ pa_assert(s);
+ pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
+ PA_CHECK_VALIDITY(s->context, sink_input_idx != PA_INVALID_INDEX, PA_ERR_INVALID);
+ PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
+ PA_CHECK_VALIDITY(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED);
+
+ s->direct_on_input = sink_input_idx;
+
+ return 0;
+}
+
+uint32_t pa_stream_get_monitor_stream(pa_stream *s) {
+ pa_assert(s);
+ pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
+ PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direct_on_input != PA_INVALID_INDEX, PA_ERR_BADSTATE, PA_INVALID_INDEX);
+ PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX);
+
+ return s->direct_on_input;
+}
diff --git a/src/pulse/stream.h b/src/pulse/stream.h
index ebb45f2b..55f36b7f 100644
--- a/src/pulse/stream.h
+++ b/src/pulse/stream.h
@@ -1,8 +1,6 @@
#ifndef foostreamhfoo
#define foostreamhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -527,14 +525,14 @@ const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s);
* server is at least PulseAudio 0.9.8. \since 0.9.8 */
pa_operation *pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata);
-/* Change the stream sampling rate during playback. You need to pass
+/** Change the stream sampling rate during playback. You need to pass
* PA_STREAM_VARIABLE_RATE in the flags parameter of
* pa_stream_connect() if you plan to use this function. Only valid
* after the stream has been connected successfully and if the server
* is at least PulseAudio 0.9.8. \since 0.9.8 */
pa_operation *pa_stream_update_sample_rate(pa_stream *s, uint32_t rate, pa_stream_success_cb_t cb, void *userdata);
-/* Update the property list of the sink input/source output of this
+/** Update the property list of the sink input/source output of this
* stream, adding new entries. Please note that it is highly
* recommended to set as much properties initially via
* pa_stream_new_with_proplist() as possible instead a posteriori with
@@ -542,10 +540,20 @@ pa_operation *pa_stream_update_sample_rate(pa_stream *s, uint32_t rate, pa_strea
* this stream to the right device. \since 0.9.11 */
pa_operation *pa_stream_proplist_update(pa_stream *s, pa_update_mode_t mode, pa_proplist *p, pa_stream_success_cb_t cb, void *userdata);
-/* Update the property list of the sink input/source output of this
+/** Update the property list of the sink input/source output of this
* stream, remove entries. \since 0.9.11 */
pa_operation *pa_stream_proplist_remove(pa_stream *s, const char *const keys[], pa_stream_success_cb_t cb, void *userdata);
+/** For record streams connected to a monitor source: monitor only a
+ * very specific sink input of the sink. Thus function needs to be
+ * called before pa_stream_connect_record() is called. \since
+ * 0.9.11 */
+int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx);
+
+/** Return what has been set with pa_stream_set_monitor_stream()
+ * ebfore. \since 0.9.11 */
+uint32_t pa_stream_get_monitor_stream(pa_stream *s);
+
PA_C_DECL_END
#endif
diff --git a/src/pulse/subscribe.c b/src/pulse/subscribe.c
index 0c5686b7..d9c06b7e 100644
--- a/src/pulse/subscribe.c
+++ b/src/pulse/subscribe.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/subscribe.h b/src/pulse/subscribe.h
index c37ead57..0e4be8c3 100644
--- a/src/pulse/subscribe.h
+++ b/src/pulse/subscribe.h
@@ -1,8 +1,6 @@
#ifndef foosubscribehfoo
#define foosubscribehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c
index e8c956bb..6b66696c 100644
--- a/src/pulse/thread-mainloop.c
+++ b/src/pulse/thread-mainloop.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h
index ea08f72a..521e29b0 100644
--- a/src/pulse/thread-mainloop.h
+++ b/src/pulse/thread-mainloop.h
@@ -1,8 +1,6 @@
#ifndef foothreadmainloophfoo
#define foothreadmainloophfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/timeval.c b/src/pulse/timeval.c
index 180e0159..9708a735 100644
--- a/src/pulse/timeval.c
+++ b/src/pulse/timeval.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -140,7 +138,7 @@ struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) {
tv->tv_usec += (suseconds_t) v;
/* Normalize */
- while (tv->tv_usec >= PA_USEC_PER_SEC) {
+ while ((unsigned) tv->tv_usec >= PA_USEC_PER_SEC) {
tv->tv_sec++;
tv->tv_usec -= PA_USEC_PER_SEC;
}
diff --git a/src/pulse/timeval.h b/src/pulse/timeval.h
index 09d53974..ee398296 100644
--- a/src/pulse/timeval.h
+++ b/src/pulse/timeval.h
@@ -1,8 +1,6 @@
#ifndef footimevalhfoo
#define footimevalhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -34,12 +32,12 @@
PA_C_DECL_BEGIN
-#define PA_MSEC_PER_SEC 1000
-#define PA_USEC_PER_SEC 1000000
-#define PA_NSEC_PER_SEC 1000000000
-#define PA_USEC_PER_MSEC 1000
-#define PA_NSEC_PER_MSEC 1000000
-#define PA_NSEC_PER_USEC 1000
+#define PA_MSEC_PER_SEC ((pa_usec_t) 1000ULL)
+#define PA_USEC_PER_SEC ((pa_usec_t) 1000000ULL)
+#define PA_NSEC_PER_SEC ((pa_usec_t) 1000000000ULL)
+#define PA_USEC_PER_MSEC ((pa_usec_t) 1000ULL)
+#define PA_NSEC_PER_MSEC ((pa_usec_t) 1000000ULL)
+#define PA_NSEC_PER_USEC ((pa_usec_t) 1000ULL)
struct timeval;
diff --git a/src/pulse/utf8.c b/src/pulse/utf8.c
index b2f6c3bd..119be542 100644
--- a/src/pulse/utf8.c
+++ b/src/pulse/utf8.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/utf8.h b/src/pulse/utf8.h
index 840c74e0..6c7e7a5b 100644
--- a/src/pulse/utf8.h
+++ b/src/pulse/utf8.h
@@ -1,8 +1,6 @@
#ifndef fooutf8hfoo
#define fooutf8hfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/util.c b/src/pulse/util.c
index b6f57b96..c0911b51 100644
--- a/src/pulse/util.c
+++ b/src/pulse/util.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/util.h b/src/pulse/util.h
index 666ccce4..cf06d4fd 100644
--- a/src/pulse/util.h
+++ b/src/pulse/util.h
@@ -1,8 +1,6 @@
#ifndef fooutilhfoo
#define fooutilhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/version.h.in b/src/pulse/version.h.in
index dc0f8e3b..e6226c44 100644
--- a/src/pulse/version.h.in
+++ b/src/pulse/version.h.in
@@ -1,8 +1,6 @@
#ifndef fooversionhfoo /*-*-C-*-*/
#define fooversionhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/volume.c b/src/pulse/volume.c
index 33ab1c5f..70d6f86a 100644
--- a/src/pulse/volume.c
+++ b/src/pulse/volume.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index e7ceb0d7..3befb1da 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -1,8 +1,6 @@
#ifndef foovolumehfoo
#define foovolumehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -103,10 +101,10 @@ PA_C_DECL_BEGIN
typedef uint32_t pa_volume_t;
/** Normal volume (100%) */
-#define PA_VOLUME_NORM ((pa_volume_t) 0x10000)
+#define PA_VOLUME_NORM ((pa_volume_t) 0x10000U)
/** Muted volume (0%) */
-#define PA_VOLUME_MUTED ((pa_volume_t) 0)
+#define PA_VOLUME_MUTED ((pa_volume_t) 0U)
/** A structure encapsulating a per-channel volume */
typedef struct pa_cvolume {
@@ -169,7 +167,7 @@ double pa_sw_volume_to_linear(pa_volume_t v) PA_GCC_CONST;
#define PA_DECIBEL_MININFTY ((double) -INFINITY)
#else
/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). */
-#define PA_DECIBEL_MININFTY ((double) -200)
+#define PA_DECIBEL_MININFTY ((double) -200.0)
#endif
PA_C_DECL_END
diff --git a/src/pulse/xmalloc.c b/src/pulse/xmalloc.c
index a64761bf..90237013 100644
--- a/src/pulse/xmalloc.c
+++ b/src/pulse/xmalloc.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulse/xmalloc.h b/src/pulse/xmalloc.h
index 62a450dc..c453138b 100644
--- a/src/pulse/xmalloc.h
+++ b/src/pulse/xmalloc.h
@@ -1,8 +1,6 @@
#ifndef foomemoryhfoo
#define foomemoryhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c
index eba1c2cb..5c7af2a8 100644
--- a/src/pulsecore/asyncmsgq.c
+++ b/src/pulsecore/asyncmsgq.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/asyncmsgq.h b/src/pulsecore/asyncmsgq.h
index 93f1ce86..1f38207a 100644
--- a/src/pulsecore/asyncmsgq.h
+++ b/src/pulsecore/asyncmsgq.h
@@ -1,8 +1,6 @@
#ifndef foopulseasyncmsgqhfoo
#define foopulseasyncmsgqhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/asyncq.c b/src/pulsecore/asyncq.c
index 8e0dfbc3..03e9f0df 100644
--- a/src/pulsecore/asyncq.c
+++ b/src/pulsecore/asyncq.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/asyncq.h b/src/pulsecore/asyncq.h
index 4cdf8cd0..e6847ab8 100644
--- a/src/pulsecore/asyncq.h
+++ b/src/pulsecore/asyncq.h
@@ -1,8 +1,6 @@
#ifndef foopulseasyncqhfoo
#define foopulseasyncqhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h
index ad3dca30..a91c4d56 100644
--- a/src/pulsecore/atomic.h
+++ b/src/pulsecore/atomic.h
@@ -1,12 +1,11 @@
#ifndef foopulseatomichfoo
#define foopulseatomichfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
- Copyright 2006 Lennart Poettering
+ Copyright 2006-2008 Lennart Poettering
+ Copyright 2008 Nokia Corporation
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
@@ -380,9 +379,9 @@ static inline int pa_atomic_dec(pa_atomic_t *a) {
/* Returns non-zero when the operation was successful. */
static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
- int failed = 1;
+ pa_bool_t failed;
do {
- failed = __kernel_cmpxchg(old_i, new_i, &a->value);
+ failed = !!__kernel_cmpxchg(old_i, new_i, &a->value);
} while(failed && a->value == old_i);
return !failed;
}
@@ -404,10 +403,10 @@ static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
}
static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
- int failed = 1;
+ pa_bool_t failed;
do {
- failed = __kernel_cmpxchg_u((unsigned long) old_p, (unsigned long) new_p, &a->value);
- } while(failed && a->value == old_p);
+ failed = !!__kernel_cmpxchg_u((unsigned long) old_p, (unsigned long) new_p, &a->value);
+ } while(failed && a->value == (unsigned long) old_p);
return !failed;
}
diff --git a/src/pulsecore/authkey-prop.c b/src/pulsecore/authkey-prop.c
index 54154500..a953bf7d 100644
--- a/src/pulsecore/authkey-prop.c
+++ b/src/pulsecore/authkey-prop.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/authkey-prop.h b/src/pulsecore/authkey-prop.h
index 247202f3..de02d2aa 100644
--- a/src/pulsecore/authkey-prop.h
+++ b/src/pulsecore/authkey-prop.h
@@ -1,8 +1,6 @@
#ifndef fooauthkeyprophfoo
#define fooauthkeyprophfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c
index 80bc8576..f3f40f80 100644
--- a/src/pulsecore/authkey.c
+++ b/src/pulsecore/authkey.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/authkey.h b/src/pulsecore/authkey.h
index 18e5157d..8301db1e 100644
--- a/src/pulsecore/authkey.h
+++ b/src/pulsecore/authkey.h
@@ -1,8 +1,6 @@
#ifndef fooauthkeyhfoo
#define fooauthkeyhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/autoload.c b/src/pulsecore/autoload.c
index a1d3e02d..26c294b2 100644
--- a/src/pulsecore/autoload.c
+++ b/src/pulsecore/autoload.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/autoload.h b/src/pulsecore/autoload.h
index 8a3522a7..3926351f 100644
--- a/src/pulsecore/autoload.h
+++ b/src/pulsecore/autoload.h
@@ -1,8 +1,6 @@
#ifndef fooautoloadhfoo
#define fooautoloadhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/avahi-wrap.c b/src/pulsecore/avahi-wrap.c
index fae54810..d5f40d83 100644
--- a/src/pulsecore/avahi-wrap.c
+++ b/src/pulsecore/avahi-wrap.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/avahi-wrap.h b/src/pulsecore/avahi-wrap.h
index 1e20ec38..7d8995bb 100644
--- a/src/pulsecore/avahi-wrap.h
+++ b/src/pulsecore/avahi-wrap.h
@@ -1,8 +1,6 @@
#ifndef fooavahiwrapperhfoo
#define fooavahiwrapperhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index 925a2e8c..cbdb602a 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/cli-command.h b/src/pulsecore/cli-command.h
index 2a923443..9bf35dc3 100644
--- a/src/pulsecore/cli-command.h
+++ b/src/pulsecore/cli-command.h
@@ -1,8 +1,6 @@
#ifndef fooclicommandhfoo
#define fooclicommandhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 029a7089..c92fca20 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -118,6 +116,9 @@ char *pa_sink_list_to_string(pa_core *c) {
for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) {
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t;
+ pa_usec_t min_latency, max_latency;
+
+ pa_sink_get_latency_range(sink, &min_latency, &max_latency);
pa_strbuf_printf(
s,
@@ -130,6 +131,8 @@ char *pa_sink_list_to_string(pa_core *c) {
"\tmuted: %s\n"
"\tcurrent latency: %0.2f ms\n"
"\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n"
+ "\tmax request: %lu KiB\n"
+ "\tmax rewind: %lu KiB\n"
"\tmonitor source: %u\n"
"\tsample spec: %s\n"
"\tchannel map: %s\n"
@@ -149,7 +152,9 @@ char *pa_sink_list_to_string(pa_core *c) {
pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink)),
pa_yes_no(pa_sink_get_mute(sink)),
(double) pa_sink_get_latency(sink) / PA_USEC_PER_MSEC,
- (double) pa_sink_get_requested_latency(sink) / PA_USEC_PER_MSEC, (double) sink->min_latency / PA_USEC_PER_MSEC, (double) sink->max_latency / PA_USEC_PER_MSEC,
+ (double) pa_sink_get_requested_latency(sink) / PA_USEC_PER_MSEC, (double) min_latency / PA_USEC_PER_MSEC, (double) max_latency / PA_USEC_PER_MSEC,
+ (unsigned long) pa_sink_get_max_request(sink) / 1024,
+ (unsigned long) pa_sink_get_max_rewind(sink) / 1024,
sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map),
@@ -186,6 +191,9 @@ char *pa_source_list_to_string(pa_core *c) {
for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) {
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], *t;
+ pa_usec_t min_latency, max_latency;
+
+ pa_source_get_latency_range(source, &min_latency, &max_latency);
pa_strbuf_printf(
s,
@@ -198,6 +206,7 @@ char *pa_source_list_to_string(pa_core *c) {
"\tmuted: %s\n"
"\tcurrent latency: %0.2f ms\n"
"\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n"
+ "\tmax rewind: %lu KiB\n"
"\tsample spec: %s\n"
"\tchannel map: %s\n"
"\tused by: %u\n"
@@ -216,7 +225,8 @@ char *pa_source_list_to_string(pa_core *c) {
pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source)),
pa_yes_no(pa_source_get_mute(source)),
(double) pa_source_get_latency(source) / PA_USEC_PER_MSEC,
- (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC, (double) source->min_latency / PA_USEC_PER_MSEC, (double) source->max_latency / PA_USEC_PER_MSEC,
+ (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC, (double) min_latency / PA_USEC_PER_MSEC, (double) max_latency / PA_USEC_PER_MSEC,
+ (unsigned long) pa_source_get_max_rewind(source) / 1024,
pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map),
pa_source_used_by(source),
@@ -287,7 +297,7 @@ char *pa_source_output_list_to_string(pa_core *c) {
o->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "",
state_table[pa_source_output_get_state(o)],
o->source->index, o->source->name,
- (double) pa_source_output_get_latency(o) / PA_USEC_PER_MSEC,
+ (double) pa_source_output_get_latency(o, NULL) / PA_USEC_PER_MSEC,
clt,
pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map),
@@ -296,6 +306,8 @@ char *pa_source_output_list_to_string(pa_core *c) {
pa_strbuf_printf(s, "\towner module: %u\n", o->module->index);
if (o->client)
pa_strbuf_printf(s, "\tclient: %u <%s>\n", o->client->index, pa_strnull(pa_proplist_gets(o->client->proplist, PA_PROP_APPLICATION_NAME)));
+ if (o->direct_on_input)
+ pa_strbuf_printf(s, "\tdirect on input: %u\n", o->direct_on_input->index);
t = pa_proplist_to_string(o->proplist);
pa_strbuf_printf(s, "\tproperties:\n%s", t);
@@ -361,7 +373,7 @@ char *pa_sink_input_list_to_string(pa_core *c) {
i->sink->index, i->sink->name,
pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)),
pa_yes_no(pa_sink_input_get_mute(i)),
- (double) pa_sink_input_get_latency(i) / PA_USEC_PER_MSEC,
+ (double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC,
clt,
pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
diff --git a/src/pulsecore/cli-text.h b/src/pulsecore/cli-text.h
index 9e5bf081..f4cb97a5 100644
--- a/src/pulsecore/cli-text.h
+++ b/src/pulsecore/cli-text.h
@@ -1,8 +1,6 @@
#ifndef fooclitexthfoo
#define fooclitexthfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c
index 47712d30..b3c639f8 100644
--- a/src/pulsecore/cli.c
+++ b/src/pulsecore/cli.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/cli.h b/src/pulsecore/cli.h
index 2b58d458..6077a8e8 100644
--- a/src/pulsecore/cli.h
+++ b/src/pulsecore/cli.h
@@ -1,8 +1,6 @@
#ifndef fooclihfoo
#define fooclihfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/client.c b/src/pulsecore/client.c
index 4eca4e2a..0ffd2330 100644
--- a/src/pulsecore/client.c
+++ b/src/pulsecore/client.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -66,18 +64,21 @@ pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) {
}
void pa_client_free(pa_client *c) {
+ pa_core *core;
+
pa_assert(c);
pa_assert(c->core);
+ core = c->core;
pa_idxset_remove_by_data(c->core->clients, c, NULL);
- pa_core_check_quit(c->core);
-
pa_log_info("Freed %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)));
pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);
pa_proplist_free(c->proplist);
pa_xfree(c->driver);
pa_xfree(c);
+
+ pa_core_check_quit(core);
}
void pa_client_kill(pa_client *c) {
diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h
index bff057ed..28d1fe5f 100644
--- a/src/pulsecore/client.h
+++ b/src/pulsecore/client.h
@@ -1,8 +1,6 @@
#ifndef foopulseclienthfoo
#define foopulseclienthfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c
index 12ea49c2..4aec45d7 100644
--- a/src/pulsecore/conf-parser.c
+++ b/src/pulsecore/conf-parser.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h
index b56d979e..7eb1fae2 100644
--- a/src/pulsecore/conf-parser.h
+++ b/src/pulsecore/conf-parser.h
@@ -1,8 +1,6 @@
#ifndef fooconfparserhfoo
#define fooconfparserhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/core-error.c b/src/pulsecore/core-error.c
index 8a61e726..3d6c2c3b 100644
--- a/src/pulsecore/core-error.c
+++ b/src/pulsecore/core-error.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/core-error.h b/src/pulsecore/core-error.h
index 443c4883..b0c306c7 100644
--- a/src/pulsecore/core-error.h
+++ b/src/pulsecore/core-error.h
@@ -1,8 +1,6 @@
#ifndef foocoreerrorhfoo
#define foocoreerrorhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c
index e5546007..75fa2ff1 100644
--- a/src/pulsecore/core-scache.c
+++ b/src/pulsecore/core-scache.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -63,7 +61,7 @@
#include "core-scache.h"
-#define UNLOAD_POLL_TIME 5
+#define UNLOAD_POLL_TIME 60
static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
pa_core *c = userdata;
@@ -131,8 +129,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) {
}
e->last_used_time = 0;
- e->memchunk.memblock = NULL;
- e->memchunk.index = e->memchunk.length = 0;
+ pa_memchunk_reset(&e->memchunk);
e->filename = NULL;
e->lazy = FALSE;
e->last_used_time = 0;
@@ -165,8 +162,7 @@ int pa_scache_add_item(
pa_assert(!map || (pa_channel_map_valid(map) && ss && ss->channels == map->channels));
if (ss && !map)
- if (!(map = pa_channel_map_init_auto(&tmap, ss->channels, PA_CHANNEL_MAP_DEFAULT)))
- return -1;
+ pa_channel_map_init_extend(&tmap, ss->channels, PA_CHANNEL_MAP_DEFAULT);
if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX)
return -1;
@@ -277,8 +273,7 @@ int pa_scache_remove_item(pa_core *c, const char *name) {
if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0)))
return -1;
- if (pa_idxset_remove_by_data(c->scache, e, NULL) != e)
- pa_assert(0);
+ pa_assert_se(pa_idxset_remove_by_data(c->scache, e, NULL) == e);
pa_log_debug("Removed sample \"%s\"", name);
diff --git a/src/pulsecore/core-scache.h b/src/pulsecore/core-scache.h
index 31f3ff32..80e0fd04 100644
--- a/src/pulsecore/core-scache.h
+++ b/src/pulsecore/core-scache.h
@@ -1,8 +1,6 @@
#ifndef foocorescachehfoo
#define foocorescachehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c
index 06c5a4ad..6107002b 100644
--- a/src/pulsecore/core-subscribe.c
+++ b/src/pulsecore/core-subscribe.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/core-subscribe.h b/src/pulsecore/core-subscribe.h
index 2b6863f9..2f9730d9 100644
--- a/src/pulsecore/core-subscribe.h
+++ b/src/pulsecore/core-subscribe.h
@@ -1,8 +1,6 @@
#ifndef foocoresubscribehfoo
#define foocoresubscribehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index c8ea4f52..d259fb16 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -1144,12 +1142,13 @@ fail:
/* Unlock a temporary lcok file */
int pa_unlock_lockfile(const char *fn, int fd) {
int r = 0;
- pa_assert(fn);
pa_assert(fd >= 0);
- if (unlink(fn) < 0) {
- pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
- r = -1;
+ if (fn) {
+ if (unlink(fn) < 0) {
+ pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
+ r = -1;
+ }
}
if (pa_lock_fd(fd, 0) < 0) {
@@ -1165,24 +1164,35 @@ int pa_unlock_lockfile(const char *fn, int fd) {
return r;
}
-char *pa_get_runtime_dir(void) {
+static char *get_dir(mode_t m, const char *env_name) {
const char *e;
char *d;
- if ((e = getenv("PULSE_RUNTIME_PATH")))
+ if ((e = getenv(env_name)))
d = pa_xstrdup(e);
else {
char h[PATH_MAX];
+ struct stat st;
if (!pa_get_home_dir(h, sizeof(h))) {
pa_log_error("Failed to get home directory.");
return NULL;
}
+ if (stat(h, &st) < 0) {
+ pa_log_error("Failed to stat home directory %s: %s", h, pa_cstrerror(errno));
+ return NULL;
+ }
+
+ if (st.st_uid != getuid()) {
+ pa_log_error("Home directory %s not ours.", d);
+ return NULL;
+ }
+
d = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
}
- if (pa_make_secure_dir(d, 0700, (pid_t) -1, (pid_t) -1) < 0) {
+ if (pa_make_secure_dir(d, m, (pid_t) -1, (pid_t) -1) < 0) {
pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
return NULL;
}
@@ -1190,6 +1200,14 @@ char *pa_get_runtime_dir(void) {
return d;
}
+char *pa_get_runtime_dir(void) {
+ return get_dir(pa_in_system_mode() ? 0755 : 0700, "PULSE_RUNTIME_PATH");
+}
+
+char *pa_get_state_dir(void) {
+ return get_dir(0700, "PULSE_STATE_PATH");
+}
+
/* Try to open a configuration file. If "env" is specified, open the
* value of the specified environment variable. Otherwise look for a
* file "local" in the home directory or a file "global" in global
@@ -1418,7 +1436,7 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
}
/* Returns nonzero when *s starts with *pfx */
-int pa_startswith(const char *s, const char *pfx) {
+pa_bool_t pa_startswith(const char *s, const char *pfx) {
size_t l;
pa_assert(s);
@@ -1430,7 +1448,7 @@ int pa_startswith(const char *s, const char *pfx) {
}
/* Returns nonzero when *s ends with *sfx */
-int pa_endswith(const char *s, const char *sfx) {
+pa_bool_t pa_endswith(const char *s, const char *sfx) {
size_t l1, l2;
pa_assert(s);
@@ -1472,13 +1490,16 @@ char *pa_make_path_absolute(const char *p) {
/* if fn is null return the PulseAudio run time path in s (~/.pulse)
* if fn is non-null and starts with / return fn
* otherwise append fn to the run time path and return it */
-char *pa_runtime_path(const char *fn) {
+static char *get_path(const char *fn, pa_bool_t rt) {
char *rtp;
if (pa_is_path_absolute(fn))
return pa_xstrdup(fn);
- rtp = pa_get_runtime_dir();
+ rtp = rt ? pa_get_runtime_dir() : pa_get_state_dir();
+
+ if (!rtp)
+ return NULL;
if (fn) {
char *r;
@@ -1489,6 +1510,14 @@ char *pa_runtime_path(const char *fn) {
return rtp;
}
+char *pa_runtime_path(const char *fn) {
+ return get_path(fn, 1);
+}
+
+char *pa_state_path(const char *fn) {
+ return get_path(fn, 0);
+}
+
/* Convert the string s to a signed integer in *ret_i */
int pa_atoi(const char *s, int32_t *ret_i) {
char *x = NULL;
@@ -1541,13 +1570,13 @@ static void c_locale_destroy(void) {
}
#endif
-int pa_atof(const char *s, float *ret_f) {
+int pa_atod(const char *s, double *ret_d) {
char *x = NULL;
- float f;
+ double f;
int r = 0;
pa_assert(s);
- pa_assert(ret_f);
+ pa_assert(ret_d);
/* This should be locale independent */
@@ -1562,22 +1591,18 @@ int pa_atof(const char *s, float *ret_f) {
if (c_locale) {
errno = 0;
- f = strtof_l(s, &x, c_locale);
+ f = strtod_l(s, &x, c_locale);
} else
#endif
{
errno = 0;
-#ifdef HAVE_STRTOF
- f = strtof(s, &x);
-#else
f = strtod(s, &x);
-#endif
}
if (!x || *x || errno != 0)
r = -1;
else
- *ret_f = f;
+ *ret_d = f;
return r;
}
@@ -1774,10 +1799,11 @@ int pa_close_all(int except_fd, ...) {
i = 0;
if (except_fd >= 0) {
+ int fd;
p[i++] = except_fd;
- while ((p[i++] = va_arg(ap, int)) >= 0)
- ;
+ while ((fd = va_arg(ap, int)) >= 0)
+ p[i++] = fd;
}
p[i] = -1;
@@ -1803,6 +1829,7 @@ int pa_close_allv(const int except_fds[]) {
struct dirent *de;
while ((de = readdir(d))) {
+ pa_bool_t found;
long l;
char *e = NULL;
int i;
@@ -1826,17 +1853,23 @@ int pa_close_allv(const int except_fds[]) {
return -1;
}
- if (fd <= 3)
+ if (fd < 3)
continue;
if (fd == dirfd(d))
continue;
+ found = FALSE;
for (i = 0; except_fds[i] >= 0; i++)
- if (except_fds[i] == fd)
- continue;
+ if (except_fds[i] == fd) {
+ found = TRUE;
+ break;
+ }
+
+ if (found)
+ continue;
- if (close(fd) < 0) {
+ if (pa_close(fd) < 0) {
saved_errno = errno;
closedir(d);
errno = saved_errno;
@@ -1890,10 +1923,11 @@ int pa_unblock_sigs(int except, ...) {
i = 0;
if (except >= 1) {
+ int sig;
p[i++] = except;
- while ((p[i++] = va_arg(ap, int)) >= 0)
- ;
+ while ((sig = va_arg(ap, int)) >= 0)
+ p[i++] = sig;
}
p[i] = -1;
@@ -1957,12 +1991,12 @@ int pa_reset_sigsv(const int except[]) {
int sig;
for (sig = 1; sig < _NSIG; sig++) {
- int reset = 1;
+ pa_bool_t reset = TRUE;
switch (sig) {
case SIGKILL:
case SIGSTOP:
- reset = 0;
+ reset = FALSE;
break;
default: {
@@ -1970,7 +2004,7 @@ int pa_reset_sigsv(const int except[]) {
for (i = 0; except[i] > 0; i++) {
if (sig == except[i]) {
- reset = 0;
+ reset = FALSE;
break;
}
}
@@ -2000,3 +2034,12 @@ void pa_set_env(const char *key, const char *value) {
putenv(pa_sprintf_malloc("%s=%s", key, value));
}
+
+pa_bool_t pa_in_system_mode(void) {
+ const char *e;
+
+ if (!(e = getenv("PULSE_SYSTEM")))
+ return FALSE;
+
+ return !!atoi(e);
+}
diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
index ec4cdc43..2ed81fc5 100644
--- a/src/pulsecore/core-util.h
+++ b/src/pulsecore/core-util.h
@@ -1,8 +1,6 @@
#ifndef foocoreutilhfoo
#define foocoreutilhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -114,18 +112,20 @@ int pa_unlock_lockfile(const char *fn, int fd);
char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength);
size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength);
-int pa_startswith(const char *s, const char *pfx) PA_GCC_PURE;
-int pa_endswith(const char *s, const char *sfx) PA_GCC_PURE;
+pa_bool_t pa_startswith(const char *s, const char *pfx) PA_GCC_PURE;
+pa_bool_t pa_endswith(const char *s, const char *sfx) PA_GCC_PURE;
FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result);
char* pa_find_config_file(const char *global, const char *local, const char *env);
char *pa_get_runtime_dir(void);
+char *pa_get_state_dir(void);
char *pa_runtime_path(const char *fn);
+char *pa_state_path(const char *fn);
int pa_atoi(const char *s, int32_t *ret_i);
int pa_atou(const char *s, uint32_t *ret_u);
-int pa_atof(const char *s, float *ret_f);
+int pa_atod(const char *s, double *ret_d);
int pa_snprintf(char *str, size_t size, const char *format, ...);
int pa_vsnprintf(char *str, size_t size, const char *format, va_list ap);
@@ -180,4 +180,8 @@ int pa_reset_sigsv(const int except[]);
void pa_set_env(const char *key, const char *value);
+pa_bool_t pa_in_system_mode(void);
+
+#define pa_streq(a,b) (!strcmp((a),(b)))
+
#endif
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index 3b758a38..b2638b10 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -135,7 +133,6 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3;
- c->is_system_instance = FALSE;
c->disallow_module_loading = FALSE;
c->realtime_scheduling = FALSE;
c->realtime_priority = 5;
@@ -210,11 +207,16 @@ static void quit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED con
void pa_core_check_quit(pa_core *c) {
pa_assert(c);
- if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_size(c->clients) == 0) {
+ if (!c->quit_event &&
+ c->exit_idle_time >= 0 &&
+ pa_idxset_size(c->clients) == 0) {
+
struct timeval tv;
pa_gettimeofday(&tv);
tv.tv_sec+= c->exit_idle_time;
+
c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c);
+
} else if (c->quit_event && pa_idxset_size(c->clients) > 0) {
c->mainloop->time_free(c->quit_event);
c->quit_event = NULL;
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index 50c05b4c..d9ed46f6 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -1,8 +1,6 @@
#ifndef foocorehfoo
#define foocorehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -123,7 +121,6 @@ struct pa_core {
pa_bool_t disallow_module_loading, running_as_daemon;
pa_resample_method_t resample_method;
- pa_bool_t is_system_instance;
pa_bool_t realtime_scheduling;
int realtime_priority;
pa_bool_t disable_remixing;
diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h
index 51dfc33d..c15c469b 100644
--- a/src/pulsecore/creds.h
+++ b/src/pulsecore/creds.h
@@ -1,8 +1,6 @@
#ifndef foocredshfoo
#define foocredshfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/dllmain.c b/src/pulsecore/dllmain.c
index 52cbf9e2..269de604 100644
--- a/src/pulsecore/dllmain.c
+++ b/src/pulsecore/dllmain.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/dynarray.c b/src/pulsecore/dynarray.c
index 8bdb46fa..a1fcd8a3 100644
--- a/src/pulsecore/dynarray.c
+++ b/src/pulsecore/dynarray.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/dynarray.h b/src/pulsecore/dynarray.h
index 0f222e10..82b42082 100644
--- a/src/pulsecore/dynarray.h
+++ b/src/pulsecore/dynarray.h
@@ -1,8 +1,6 @@
#ifndef foodynarrayhfoo
#define foodynarrayhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/endianmacros.h b/src/pulsecore/endianmacros.h
index 6b80246b..26336918 100644
--- a/src/pulsecore/endianmacros.h
+++ b/src/pulsecore/endianmacros.h
@@ -1,8 +1,6 @@
#ifndef fooendianmacroshfoo
#define fooendianmacroshfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/envelope.c b/src/pulsecore/envelope.c
index 2f5da5a0..e2691611 100644
--- a/src/pulsecore/envelope.c
+++ b/src/pulsecore/envelope.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/envelope.h b/src/pulsecore/envelope.h
index c54c137a..5296415a 100644
--- a/src/pulsecore/envelope.h
+++ b/src/pulsecore/envelope.h
@@ -1,8 +1,6 @@
#ifndef foopulseenvelopehfoo
#define foopulseenvelopehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/esound.h b/src/pulsecore/esound.h
index ea6a5665..79322ae4 100644
--- a/src/pulsecore/esound.h
+++ b/src/pulsecore/esound.h
@@ -1,8 +1,6 @@
#ifndef fooesoundhfoo
#define fooesoundhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/fdsem.c b/src/pulsecore/fdsem.c
index 22d2a850..1531e3db 100644
--- a/src/pulsecore/fdsem.c
+++ b/src/pulsecore/fdsem.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/fdsem.h b/src/pulsecore/fdsem.h
index f4f7b99a..48a77c49 100644
--- a/src/pulsecore/fdsem.h
+++ b/src/pulsecore/fdsem.h
@@ -1,8 +1,6 @@
#ifndef foopulsefdsemhfoo
#define foopulsefdsemhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c
index d9740777..f166ee33 100644
--- a/src/pulsecore/flist.c
+++ b/src/pulsecore/flist.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/flist.h b/src/pulsecore/flist.h
index 3d9a89a2..c040667d 100644
--- a/src/pulsecore/flist.h
+++ b/src/pulsecore/flist.h
@@ -1,8 +1,6 @@
#ifndef foopulseflisthfoo
#define foopulseflisthfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/hashmap.c b/src/pulsecore/hashmap.c
index c9d5632c..b7f4109b 100644
--- a/src/pulsecore/hashmap.c
+++ b/src/pulsecore/hashmap.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -191,24 +189,36 @@ unsigned pa_hashmap_size(pa_hashmap *h) {
}
void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) {
+ struct hashmap_entry *e;
+
pa_assert(h);
pa_assert(state);
- if (!*state)
- *state = h->first_entry;
+ if (*state == (void*) -1)
+ goto at_end;
+
+ if ((!*state && !h->first_entry))
+ goto at_end;
+
+ e = *state ? *state : h->first_entry;
+
+ if (e->next)
+ *state = e->next;
else
- *state = ((struct hashmap_entry*) *state)->next;
+ *state = (void*) -1;
- if (!*state) {
- if (key)
- *key = NULL;
- return NULL;
- }
+ if (key)
+ *key = e->key;
+
+ return e->value;
+
+at_end:
+ *state = (void *) -1;
if (key)
- *key = ((struct hashmap_entry*) *state)->key;
+ *key = NULL;
- return ((struct hashmap_entry*) *state)->value;
+ return NULL;
}
void* pa_hashmap_steal_first(pa_hashmap *h) {
diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h
index 98df4502..a4505c4c 100644
--- a/src/pulsecore/hashmap.h
+++ b/src/pulsecore/hashmap.h
@@ -1,8 +1,6 @@
#ifndef foohashmaphfoo
#define foohashmaphfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -51,9 +49,10 @@ unsigned pa_hashmap_size(pa_hashmap *h);
/* May be used to iterate through the hashmap. Initially the opaque
pointer *state has to be set to NULL. The hashmap may not be
- modified during iteration. The key of the entry is returned in
- *key, if key is non-NULL. After the last entry in the hashmap NULL
- is returned. */
+ modified during iteration -- except for deleting the current entry
+ via pa_hashmap_remove(). The key of the entry is returned in *key,
+ if key is non-NULL. After the last entry in the hashmap NULL is
+ returned. */
void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void**key);
void *pa_hashmap_steal_first(pa_hashmap *h);
diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c
index 3a6874c4..0aac4759 100644
--- a/src/pulsecore/hook-list.c
+++ b/src/pulsecore/hook-list.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -33,8 +31,7 @@ void pa_hook_init(pa_hook *hook, void *data) {
pa_assert(hook);
PA_LLIST_HEAD_INIT(pa_hook_slot, hook->slots);
- hook->last = NULL;
- hook->n_dead = hook->firing = 0;
+ hook->n_dead = hook->n_firing = 0;
hook->data = data;
}
@@ -42,9 +39,6 @@ static void slot_free(pa_hook *hook, pa_hook_slot *slot) {
pa_assert(hook);
pa_assert(slot);
- if (hook->last == slot)
- hook->last = slot->prev;
-
PA_LLIST_REMOVE(pa_hook_slot, hook->slots, slot);
pa_xfree(slot);
@@ -52,7 +46,7 @@ static void slot_free(pa_hook *hook, pa_hook_slot *slot) {
void pa_hook_free(pa_hook *hook) {
pa_assert(hook);
- pa_assert(!hook->firing);
+ pa_assert(hook->n_firing == 0);
while (hook->slots)
slot_free(hook, hook->slots);
@@ -60,19 +54,26 @@ void pa_hook_free(pa_hook *hook) {
pa_hook_init(hook, NULL);
}
-pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *data) {
- pa_hook_slot *slot;
+pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_priority_t prio, pa_hook_cb_t cb, void *data) {
+ pa_hook_slot *slot, *where, *prev;
pa_assert(cb);
slot = pa_xnew(pa_hook_slot, 1);
slot->hook = hook;
- slot->dead = 0;
+ slot->dead = FALSE;
slot->callback = cb;
slot->data = data;
+ slot->priority = prio;
- PA_LLIST_INSERT_AFTER(pa_hook_slot, hook->slots, hook->last, slot);
- hook->last = slot;
+ prev = NULL;
+ for (where = hook->slots; where; where = where->next) {
+ if (prio < where->priority)
+ break;
+ prev = where;
+ }
+
+ PA_LLIST_INSERT_AFTER(pa_hook_slot, hook->slots, prev, slot);
return slot;
}
@@ -81,8 +82,8 @@ void pa_hook_slot_free(pa_hook_slot *slot) {
pa_assert(slot);
pa_assert(!slot->dead);
- if (slot->hook->firing > 0) {
- slot->dead = 1;
+ if (slot->hook->n_firing > 0) {
+ slot->dead = TRUE;
slot->hook->n_dead++;
} else
slot_free(slot->hook, slot);
@@ -94,7 +95,7 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) {
pa_assert(hook);
- hook->firing ++;
+ hook->n_firing ++;
for (slot = hook->slots; slot; slot = slot->next) {
if (slot->dead)
@@ -104,7 +105,8 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) {
break;
}
- hook->firing --;
+ hook->n_firing --;
+ pa_assert(hook->n_firing >= 0);
for (slot = hook->slots; hook->n_dead > 0 && slot; slot = next) {
next = slot->next;
@@ -115,6 +117,7 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) {
}
}
+ pa_assert(hook->n_dead == 0);
+
return result;
}
-
diff --git a/src/pulsecore/hook-list.h b/src/pulsecore/hook-list.h
index c288980d..cf85aca5 100644
--- a/src/pulsecore/hook-list.h
+++ b/src/pulsecore/hook-list.h
@@ -1,8 +1,6 @@
#ifndef foohooklistfoo
#define foohooklistfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -38,14 +36,21 @@ typedef enum pa_hook_result {
PA_HOOK_CANCEL = -1
} pa_hook_result_t;
+typedef enum pa_hook_priority {
+ PA_HOOK_EARLY = -100,
+ PA_HOOK_NORMAL = 0,
+ PA_HOOK_LATE = 100
+} pa_hook_priority_t;
+
typedef pa_hook_result_t (*pa_hook_cb_t)(
void *hook_data,
void *call_data,
void *slot_data);
struct pa_hook_slot {
- int dead;
+ pa_bool_t dead;
pa_hook *hook;
+ pa_hook_priority_t priority;
pa_hook_cb_t callback;
void *data;
PA_LLIST_FIELDS(pa_hook_slot);
@@ -53,8 +58,7 @@ struct pa_hook_slot {
struct pa_hook {
PA_LLIST_HEAD(pa_hook_slot, slots);
- pa_hook_slot *last;
- int firing, n_dead;
+ int n_firing, n_dead;
void *data;
};
@@ -62,7 +66,7 @@ struct pa_hook {
void pa_hook_init(pa_hook *hook, void *data);
void pa_hook_free(pa_hook *hook);
-pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t, void *data);
+pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_priority_t prio, pa_hook_cb_t cb, void *data);
void pa_hook_slot_free(pa_hook_slot *slot);
pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data);
diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c
index 8a88471f..7c9520a4 100644
--- a/src/pulsecore/idxset.c
+++ b/src/pulsecore/idxset.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/idxset.h b/src/pulsecore/idxset.h
index 5b55cec2..0a4e528e 100644
--- a/src/pulsecore/idxset.h
+++ b/src/pulsecore/idxset.h
@@ -1,8 +1,6 @@
#ifndef fooidxsethfoo
#define fooidxsethfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/inet_ntop.c b/src/pulsecore/inet_ntop.c
index 4a4f7aac..87551232 100644
--- a/src/pulsecore/inet_ntop.c
+++ b/src/pulsecore/inet_ntop.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/inet_pton.c b/src/pulsecore/inet_pton.c
index 84d0c0ea..d191e550 100644
--- a/src/pulsecore/inet_pton.c
+++ b/src/pulsecore/inet_pton.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c
index 63ab2ad7..b40c9815 100644
--- a/src/pulsecore/iochannel.c
+++ b/src/pulsecore/iochannel.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -424,3 +422,16 @@ int pa_iochannel_get_send_fd(pa_iochannel *io) {
return io->ofd;
}
+
+pa_bool_t pa_iochannel_socket_is_local(pa_iochannel *io) {
+ pa_assert(io);
+
+ if (pa_socket_is_local(io->ifd))
+ return TRUE;
+
+ if (io->ifd != io->ofd)
+ if (pa_socket_is_local(io->ofd))
+ return TRUE;
+
+ return FALSE;
+}
diff --git a/src/pulsecore/iochannel.h b/src/pulsecore/iochannel.h
index c9794d99..9050df90 100644
--- a/src/pulsecore/iochannel.h
+++ b/src/pulsecore/iochannel.h
@@ -1,8 +1,6 @@
#ifndef fooiochannelhfoo
#define fooiochannelhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -85,6 +83,8 @@ void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l);
int pa_iochannel_socket_set_rcvbuf(pa_iochannel*io, size_t l);
int pa_iochannel_socket_set_sndbuf(pa_iochannel*io, size_t l);
+pa_bool_t pa_iochannel_socket_is_local(pa_iochannel *io);
+
pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io);
int pa_iochannel_get_recv_fd(pa_iochannel *io);
diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c
index 85bbadc4..90afaafd 100644
--- a/src/pulsecore/ioline.c
+++ b/src/pulsecore/ioline.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/ioline.h b/src/pulsecore/ioline.h
index f4edc7b4..b9a3d9f4 100644
--- a/src/pulsecore/ioline.h
+++ b/src/pulsecore/ioline.h
@@ -1,8 +1,6 @@
#ifndef fooiolinehfoo
#define fooiolinehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c
index 9b22e8f5..7b5f865b 100644
--- a/src/pulsecore/ipacl.c
+++ b/src/pulsecore/ipacl.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/ipacl.h b/src/pulsecore/ipacl.h
index 175f54e0..7b7ffa61 100644
--- a/src/pulsecore/ipacl.h
+++ b/src/pulsecore/ipacl.h
@@ -1,8 +1,6 @@
#ifndef fooparseaddrhfoo
#define fooparseaddrhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/llist.h b/src/pulsecore/llist.h
index e62f15b4..46b54eb3 100644
--- a/src/pulsecore/llist.h
+++ b/src/pulsecore/llist.h
@@ -1,8 +1,6 @@
#ifndef foollistfoo
#define foollistfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c
index b5929ec4..5eda4f65 100644
--- a/src/pulsecore/log.c
+++ b/src/pulsecore/log.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h
index 765dd2e5..2047696e 100644
--- a/src/pulsecore/log.h
+++ b/src/pulsecore/log.h
@@ -1,8 +1,6 @@
#ifndef foologhfoo
#define foologhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/ltdl-helper.c b/src/pulsecore/ltdl-helper.c
index b83897a6..0d4c22f8 100644
--- a/src/pulsecore/ltdl-helper.c
+++ b/src/pulsecore/ltdl-helper.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/ltdl-helper.h b/src/pulsecore/ltdl-helper.h
index 5c7388a1..ea73de54 100644
--- a/src/pulsecore/ltdl-helper.h
+++ b/src/pulsecore/ltdl-helper.h
@@ -1,8 +1,6 @@
#ifndef foopulsecoreltdlhelperhfoo
#define foopulsecoreltdlhelperhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h
index 1d9eafd5..fd33b7bb 100644
--- a/src/pulsecore/macro.h
+++ b/src/pulsecore/macro.h
@@ -1,8 +1,6 @@
#ifndef foopulsemacrohfoo
#define foopulsemacrohfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/mcalign.c b/src/pulsecore/mcalign.c
index e12f84f8..a03d5ae7 100644
--- a/src/pulsecore/mcalign.c
+++ b/src/pulsecore/mcalign.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/mcalign.h b/src/pulsecore/mcalign.h
index 6c8b8d5f..e82eb007 100644
--- a/src/pulsecore/mcalign.h
+++ b/src/pulsecore/mcalign.h
@@ -1,8 +1,6 @@
#ifndef foomcalignhfoo
#define foomcalignhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c
index 7005b441..c2ee1360 100644
--- a/src/pulsecore/memblock.c
+++ b/src/pulsecore/memblock.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h
index 8dc3f5a3..efe55b02 100644
--- a/src/pulsecore/memblock.h
+++ b/src/pulsecore/memblock.h
@@ -1,8 +1,6 @@
#ifndef foopulsememblockhfoo
#define foopulsememblockhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c
index c047e56f..a9f28a07 100644
--- a/src/pulsecore/memblockq.c
+++ b/src/pulsecore/memblockq.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -786,6 +784,9 @@ void pa_memblockq_set_tlength(pa_memblockq *bq, size_t tlength) {
if (bq->tlength > bq->maxlength)
bq->tlength = bq->maxlength;
+ if (bq->prebuf > bq->tlength)
+ pa_memblockq_set_prebuf(bq, bq->tlength);
+
if (bq->minreq > bq->tlength)
pa_memblockq_set_minreq(bq, bq->tlength);
@@ -803,8 +804,8 @@ void pa_memblockq_set_prebuf(pa_memblockq *bq, size_t prebuf) {
if (prebuf > 0 && bq->prebuf < bq->base)
bq->prebuf = bq->base;
- if (bq->prebuf > bq->maxlength)
- bq->prebuf = bq->maxlength;
+ if (bq->prebuf > bq->tlength)
+ bq->prebuf = bq->tlength;
if (bq->prebuf <= 0 || pa_memblockq_get_length(bq) >= bq->prebuf)
bq->in_prebuf = FALSE;
@@ -908,3 +909,9 @@ unsigned pa_memblockq_get_nblocks(pa_memblockq *bq) {
return bq->n_blocks;
}
+
+size_t pa_memblockq_get_base(pa_memblockq *bq) {
+ pa_assert(bq);
+
+ return bq->base;
+}
diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h
index 7c38757f..81f7cbb8 100644
--- a/src/pulsecore/memblockq.h
+++ b/src/pulsecore/memblockq.h
@@ -1,8 +1,6 @@
#ifndef foomemblockqhfoo
#define foomemblockqhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -169,4 +167,6 @@ pa_bool_t pa_memblockq_prebuf_active(pa_memblockq *bq);
unsigned pa_memblockq_get_nblocks(pa_memblockq *bq);
+size_t pa_memblockq_get_base(pa_memblockq *bq);
+
#endif
diff --git a/src/pulsecore/memchunk.c b/src/pulsecore/memchunk.c
index 16a9c140..0bbf8590 100644
--- a/src/pulsecore/memchunk.c
+++ b/src/pulsecore/memchunk.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -49,17 +47,20 @@ pa_memchunk* pa_memchunk_make_writable(pa_memchunk *c, size_t min) {
pa_memblock_get_length(c->memblock) >= c->index+min)
return c;
- l = c->length;
- if (l < min)
- l = min;
+ l = PA_MAX(c->length, min);
n = pa_memblock_new(pa_memblock_get_pool(c->memblock), l);
- tdata = pa_memblock_acquire(n);
+
sdata = pa_memblock_acquire(c->memblock);
+ tdata = pa_memblock_acquire(n);
+
memcpy(tdata, (uint8_t*) sdata + c->index, c->length);
- pa_memblock_release(n);
+
pa_memblock_release(c->memblock);
+ pa_memblock_release(n);
+
pa_memblock_unref(c->memblock);
+
c->memblock = n;
c->index = 0;
@@ -69,8 +70,7 @@ pa_memchunk* pa_memchunk_make_writable(pa_memchunk *c, size_t min) {
pa_memchunk* pa_memchunk_reset(pa_memchunk *c) {
pa_assert(c);
- c->memblock = NULL;
- c->length = c->index = 0;
+ memset(c, 0, sizeof(*c));
return c;
}
diff --git a/src/pulsecore/memchunk.h b/src/pulsecore/memchunk.h
index 46a82406..9458f4ff 100644
--- a/src/pulsecore/memchunk.h
+++ b/src/pulsecore/memchunk.h
@@ -1,8 +1,6 @@
#ifndef foomemchunkhfoo
#define foomemchunkhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c
index 0dab254b..5f5902c9 100644
--- a/src/pulsecore/modargs.c
+++ b/src/pulsecore/modargs.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -53,6 +51,12 @@ static int add_key_value(pa_hashmap *map, char *key, char *value, const char* co
pa_assert(key);
pa_assert(value);
+ if (pa_hashmap_get(map, key)) {
+ pa_xfree(key);
+ pa_xfree(value);
+ return -1;
+ }
+
if (valid_keys) {
const char*const* v;
for (v = valid_keys; *v; v++)
@@ -80,7 +84,15 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) {
map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
if (args) {
- enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state;
+ enum {
+ WHITESPACE,
+ KEY,
+ VALUE_START,
+ VALUE_SIMPLE,
+ VALUE_DOUBLE_QUOTES,
+ VALUE_TICKS
+ } state;
+
const char *p, *key, *value;
size_t key_len = 0, value_len = 0;
@@ -100,6 +112,8 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) {
case KEY:
if (*p == '=')
state = VALUE_START;
+ else if (isspace(*p))
+ goto fail;
else
key_len++;
break;
diff --git a/src/pulsecore/modargs.h b/src/pulsecore/modargs.h
index 504b9cd7..23766cfc 100644
--- a/src/pulsecore/modargs.h
+++ b/src/pulsecore/modargs.h
@@ -1,8 +1,6 @@
#ifndef foomodargshfoo
#define foomodargshfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/modinfo.c b/src/pulsecore/modinfo.c
index d1a78fbb..ac4ca88a 100644
--- a/src/pulsecore/modinfo.c
+++ b/src/pulsecore/modinfo.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/modinfo.h b/src/pulsecore/modinfo.h
index da6d5428..605637c4 100644
--- a/src/pulsecore/modinfo.h
+++ b/src/pulsecore/modinfo.h
@@ -1,8 +1,6 @@
#ifndef foomodinfohfoo
#define foomodinfohfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c
index 8e5bd2d1..f1eeb762 100644
--- a/src/pulsecore/module.c
+++ b/src/pulsecore/module.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -120,7 +118,7 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
if (!c->modules)
c->modules = pa_idxset_new(NULL, NULL);
- if (!c->module_auto_unload_event) {
+ if (m->auto_unload && !c->module_auto_unload_event) {
struct timeval ntv;
pa_gettimeofday(&ntv);
pa_timeval_add(&ntv, UNLOAD_POLL_TIME*1000000);
diff --git a/src/pulsecore/module.h b/src/pulsecore/module.h
index 68c7238d..ec582f25 100644
--- a/src/pulsecore/module.h
+++ b/src/pulsecore/module.h
@@ -1,8 +1,6 @@
#ifndef foomodulehfoo
#define foomodulehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/msgobject.c b/src/pulsecore/msgobject.c
index f54e69f2..81417ea4 100644
--- a/src/pulsecore/msgobject.c
+++ b/src/pulsecore/msgobject.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/msgobject.h b/src/pulsecore/msgobject.h
index 8221cc33..1a43fa35 100644
--- a/src/pulsecore/msgobject.h
+++ b/src/pulsecore/msgobject.h
@@ -1,8 +1,6 @@
#ifndef foopulsemsgobjecthfoo
#define foopulsemsgobjecthfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/mutex-posix.c b/src/pulsecore/mutex-posix.c
index 6ac98484..35465b7b 100644
--- a/src/pulsecore/mutex-posix.c
+++ b/src/pulsecore/mutex-posix.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/mutex-win32.c b/src/pulsecore/mutex-win32.c
index 77d63d15..5e884e7f 100644
--- a/src/pulsecore/mutex-win32.c
+++ b/src/pulsecore/mutex-win32.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/mutex.h b/src/pulsecore/mutex.h
index 9ca8fae5..36e1d635 100644
--- a/src/pulsecore/mutex.h
+++ b/src/pulsecore/mutex.h
@@ -1,8 +1,6 @@
#ifndef foopulsemutexhfoo
#define foopulsemutexhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c
index 1b0977d7..cc18adab 100644
--- a/src/pulsecore/namereg.c
+++ b/src/pulsecore/namereg.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h
index 0f5b4d4d..af0153ec 100644
--- a/src/pulsecore/namereg.h
+++ b/src/pulsecore/namereg.h
@@ -1,8 +1,6 @@
#ifndef foonamereghfoo
#define foonamereghfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h
index 56f9037e..809d6c75 100644
--- a/src/pulsecore/native-common.h
+++ b/src/pulsecore/native-common.h
@@ -1,8 +1,6 @@
#ifndef foonativecommonhfoo
#define foonativecommonhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/object.c b/src/pulsecore/object.c
index 6c36242b..9a2f28f3 100644
--- a/src/pulsecore/object.c
+++ b/src/pulsecore/object.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/object.h b/src/pulsecore/object.h
index 562fd113..7dcfa2eb 100644
--- a/src/pulsecore/object.h
+++ b/src/pulsecore/object.h
@@ -1,8 +1,6 @@
#ifndef foopulseobjecthfoo
#define foopulseobjecthfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/once.c b/src/pulsecore/once.c
index a358cf65..989741dc 100644
--- a/src/pulsecore/once.c
+++ b/src/pulsecore/once.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/once.h b/src/pulsecore/once.h
index c9fe6d0a..576d40fa 100644
--- a/src/pulsecore/once.h
+++ b/src/pulsecore/once.h
@@ -1,8 +1,6 @@
#ifndef foopulseoncehfoo
#define foopulseoncehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/packet.c b/src/pulsecore/packet.c
index 2706efea..cee468bd 100644
--- a/src/pulsecore/packet.c
+++ b/src/pulsecore/packet.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/packet.h b/src/pulsecore/packet.h
index bcac4a7f..5989b1fa 100644
--- a/src/pulsecore/packet.h
+++ b/src/pulsecore/packet.h
@@ -1,8 +1,6 @@
#ifndef foopackethfoo
#define foopackethfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/parseaddr.c b/src/pulsecore/parseaddr.c
index 149c9e00..f2b6b2cf 100644
--- a/src/pulsecore/parseaddr.c
+++ b/src/pulsecore/parseaddr.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/parseaddr.h b/src/pulsecore/parseaddr.h
index fd7cad3b..5fbcb9a7 100644
--- a/src/pulsecore/parseaddr.h
+++ b/src/pulsecore/parseaddr.h
@@ -1,8 +1,6 @@
#ifndef fooparseaddrhfoo
#define fooparseaddrhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c
index bdd7cde1..e6a6ae4d 100644
--- a/src/pulsecore/pdispatch.c
+++ b/src/pulsecore/pdispatch.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/pdispatch.h b/src/pulsecore/pdispatch.h
index de0aa3ec..5c31d80e 100644
--- a/src/pulsecore/pdispatch.h
+++ b/src/pulsecore/pdispatch.h
@@ -1,8 +1,6 @@
#ifndef foopdispatchhfoo
#define foopdispatchhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c
index 2ff132bb..addb17cc 100644
--- a/src/pulsecore/pid.c
+++ b/src/pulsecore/pid.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -140,8 +138,51 @@ fail:
return -1;
}
+static int proc_name_ours(pid_t pid, const char *procname) {
+#ifdef __linux__
+ char bn[PATH_MAX];
+ FILE *f;
+
+ pa_snprintf(bn, sizeof(bn), "/proc/%lu/stat", (unsigned long) pid);
+
+ if (!(f = fopen(bn, "r"))) {
+ pa_log_info("Failed to open %s: %s", bn, pa_cstrerror(errno));
+ return -1;
+ } else {
+ char *expected;
+ pa_bool_t good;
+ char stored[64];
+
+ if (!(fgets(stored, sizeof(stored), f))) {
+ pa_log_info("Failed to read from %s: %s", bn, feof(f) ? "EOF" : pa_cstrerror(errno));
+ fclose(f);
+ return -1;
+ }
+
+ fclose(f);
+
+ expected = pa_sprintf_malloc("%lu (%s)", (unsigned long) pid, procname);
+ good = pa_startswith(stored, expected);
+ pa_xfree(expected);
+
+#if !defined(__OPTIMIZE__)
+ if (!good) {
+ /* libtool likes to rename our binary names ... */
+ expected = pa_sprintf_malloc("%lu (lt-%s)", (unsigned long) pid, procname);
+ good = pa_startswith(stored, expected);
+ pa_xfree(expected);
+ }
+#endif
+
+ return !!good;
+ }
+#endif
+
+ return 1;
+}
+
/* Create a new PID file for the current process. */
-int pa_pid_file_create(void) {
+int pa_pid_file_create(const char *procname) {
int fd = -1;
int ret = -1;
char t[20];
@@ -153,7 +194,8 @@ int pa_pid_file_create(void) {
HANDLE process;
#endif
- fn = pa_runtime_path("pid");
+ if (!(fn = pa_runtime_path("pid")))
+ goto fail;
if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0)
goto fail;
@@ -161,14 +203,24 @@ int pa_pid_file_create(void) {
if ((pid = read_pid(fn, fd)) == (pid_t) -1)
pa_log_warn("Corrupt PID file, overwriting.");
else if (pid > 0) {
+
#ifdef OS_IS_WIN32
if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) {
CloseHandle(process);
#else
if (kill(pid, 0) >= 0 || errno != ESRCH) {
#endif
- pa_log("Daemon already running.");
- goto fail;
+ int ours = 1;
+
+ if (procname)
+ if ((ours = proc_name_ours(pid, procname)) < 0)
+ goto fail;
+
+ if (ours) {
+ pa_log("Daemon already running.");
+ ret = 1;
+ goto fail;
+ }
}
pa_log_warn("Stale PID file, overwriting.");
@@ -212,7 +264,8 @@ int pa_pid_file_remove(void) {
int ret = -1;
pid_t pid;
- fn = pa_runtime_path("pid");
+ if (!(fn = pa_runtime_path("pid")))
+ goto fail;
if ((fd = open_pid_file(fn, O_RDWR)) < 0) {
pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno));
@@ -234,7 +287,7 @@ int pa_pid_file_remove(void) {
#ifdef OS_IS_WIN32
pa_lock_fd(fd, 0);
- close(fd);
+ pa_close(fd);
fd = -1;
#endif
@@ -265,8 +318,8 @@ fail:
* exists and the PID therein too. Returns 0 on succcess, -1
* otherwise. If pid is non-NULL and a running daemon was found,
* return its PID therein */
-int pa_pid_file_check_running(pid_t *pid, const char *binary_name) {
- return pa_pid_file_kill(0, pid, binary_name);
+int pa_pid_file_check_running(pid_t *pid, const char *procname) {
+ return pa_pid_file_kill(0, pid, procname);
}
#ifndef OS_IS_WIN32
@@ -274,7 +327,7 @@ int pa_pid_file_check_running(pid_t *pid, const char *binary_name) {
/* Kill a current running daemon. Return non-zero on success, -1
* otherwise. If successful *pid contains the PID of the daemon
* process. */
-int pa_pid_file_kill(int sig, pid_t *pid, const char *binary_name) {
+int pa_pid_file_kill(int sig, pid_t *pid, const char *procname) {
int fd = -1;
char *fn;
int ret = -1;
@@ -282,10 +335,12 @@ int pa_pid_file_kill(int sig, pid_t *pid, const char *binary_name) {
#ifdef __linux__
char *e = NULL;
#endif
+
if (!pid)
pid = &_pid;
- fn = pa_runtime_path("pid");
+ if (!(fn = pa_runtime_path("pid")))
+ goto fail;
if ((fd = open_pid_file(fn, O_RDONLY)) < 0)
goto fail;
@@ -293,22 +348,15 @@ int pa_pid_file_kill(int sig, pid_t *pid, const char *binary_name) {
if ((*pid = read_pid(fn, fd)) == (pid_t) -1)
goto fail;
-#ifdef __linux__
- if (binary_name) {
- pa_snprintf(fn, sizeof(fn), "/proc/%lu/exe", (unsigned long) pid);
+ if (procname) {
+ int ours;
- if ((e = pa_readlink(fn))) {
- char *f = pa_path_get_filename(e);
- if (strcmp(f, binary_name)
-#if !defined(__OPTIMIZE__)
- /* libtool likes to rename our binary names ... */
- && !(pa_startswith(f, "lt-") && strcmp(f+3, binary_name) == 0)
-#endif
- )
- goto fail;
- }
+ if ((ours = proc_name_ours(*pid, procname)) < 0)
+ goto fail;
+
+ if (!ours)
+ goto fail;
}
-#endif
ret = kill(*pid, sig);
diff --git a/src/pulsecore/pid.h b/src/pulsecore/pid.h
index 1d6de7b5..3c8a9de3 100644
--- a/src/pulsecore/pid.h
+++ b/src/pulsecore/pid.h
@@ -1,8 +1,6 @@
#ifndef foopidhfoo
#define foopidhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -24,9 +22,9 @@
USA.
***/
-int pa_pid_file_create(void);
+int pa_pid_file_create(const char *procname);
int pa_pid_file_remove(void);
-int pa_pid_file_check_running(pid_t *pid, const char *binary_name);
-int pa_pid_file_kill(int sig, pid_t *pid, const char *binary_name);
+int pa_pid_file_check_running(pid_t *pid, const char *procname);
+int pa_pid_file_kill(int sig, pid_t *pid, const char *procname);
#endif
diff --git a/src/pulsecore/pipe.c b/src/pulsecore/pipe.c
index e614c9c6..93d78a22 100644
--- a/src/pulsecore/pipe.c
+++ b/src/pulsecore/pipe.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/pipe.h b/src/pulsecore/pipe.h
index e013a2e7..9a7e62c8 100644
--- a/src/pulsecore/pipe.h
+++ b/src/pulsecore/pipe.h
@@ -1,8 +1,6 @@
#ifndef foopipehfoo
#define foopipehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c
index 2688f923..8b3e79b9 100644
--- a/src/pulsecore/play-memblockq.c
+++ b/src/pulsecore/play-memblockq.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -138,6 +136,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
return -1;
}
+ chunk->length = PA_MIN(chunk->length, nbytes);
pa_memblockq_drop(u->memblockq, chunk->length);
return 0;
diff --git a/src/pulsecore/play-memblockq.h b/src/pulsecore/play-memblockq.h
index 9ecf7700..1a42867b 100644
--- a/src/pulsecore/play-memblockq.h
+++ b/src/pulsecore/play-memblockq.h
@@ -1,8 +1,6 @@
#ifndef fooplaymemblockqhfoo
#define fooplaymemblockqhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/play-memchunk.c b/src/pulsecore/play-memchunk.c
index 67a92138..0dd48251 100644
--- a/src/pulsecore/play-memchunk.c
+++ b/src/pulsecore/play-memchunk.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/play-memchunk.h b/src/pulsecore/play-memchunk.h
index f7c9d178..c312ae82 100644
--- a/src/pulsecore/play-memchunk.h
+++ b/src/pulsecore/play-memchunk.h
@@ -1,8 +1,6 @@
#ifndef fooplaychunkhfoo
#define fooplaychunkhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c
index 288f7dfb..88ac21e4 100644
--- a/src/pulsecore/poll.c
+++ b/src/pulsecore/poll.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/poll.h b/src/pulsecore/poll.h
index 6be6069b..86c37a08 100644
--- a/src/pulsecore/poll.h
+++ b/src/pulsecore/poll.h
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c
new file mode 100644
index 00000000..6005775e
--- /dev/null
+++ b/src/pulsecore/proplist-util.c
@@ -0,0 +1,118 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2008 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 <string.h>
+#include <locale.h>
+
+#include <pulse/proplist.h>
+#include <pulse/utf8.h>
+#include <pulse/xmalloc.h>
+#include <pulse/util.h>
+
+#include <pulsecore/core-util.h>
+
+#include "proplist-util.h"
+
+void pa_init_proplist(pa_proplist *p) {
+ int a, b;
+#ifndef HAVE_DECL_ENVIRON
+ extern char **environ;
+#endif
+ char **e;
+
+ pa_assert(p);
+
+ for (e = environ; *e; e++) {
+
+ if (pa_startswith(*e, "PULSE_PROP_")) {
+ size_t kl = strcspn(*e+11, "=");
+ char *k;
+
+ if ((*e)[11+kl] != '=')
+ continue;
+
+ if (!pa_utf8_valid(*e+11+kl+1))
+ continue;
+
+ k = pa_xstrndup(*e+11, kl);
+
+ if (pa_proplist_contains(p, k)) {
+ pa_xfree(k);
+ continue;
+ }
+
+ pa_proplist_sets(p, k, *e+11+kl+1);
+ pa_xfree(k);
+ }
+ }
+
+ if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_ID)) {
+ char t[32];
+ pa_snprintf(t, sizeof(t), "%lu", (unsigned long) getpid());
+ pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_ID, t);
+ }
+
+ if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_USER)) {
+ char t[64];
+ if (pa_get_user_name(t, sizeof(t))) {
+ char *c = pa_utf8_filter(t);
+ pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_USER, c);
+ pa_xfree(c);
+ }
+ }
+
+ if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_HOST)) {
+ char t[64];
+ if (pa_get_host_name(t, sizeof(t))) {
+ char *c = pa_utf8_filter(t);
+ pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_HOST, c);
+ pa_xfree(c);
+ }
+ }
+
+ a = pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_BINARY);
+ b = pa_proplist_contains(p, PA_PROP_APPLICATION_NAME);
+
+ if (!a || !b) {
+ char t[PATH_MAX];
+ if (pa_get_binary_name(t, sizeof(t))) {
+ char *c = pa_utf8_filter(t);
+
+ if (!a)
+ pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_BINARY, c);
+ if (!b)
+ pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, c);
+
+ pa_xfree(c);
+ }
+ }
+
+ if (!pa_proplist_contains(p, PA_PROP_APPLICATION_LANGUAGE)) {
+ const char *l;
+
+ if ((l = setlocale(LC_MESSAGES, NULL)))
+ pa_proplist_sets(p, PA_PROP_APPLICATION_LANGUAGE, l);
+ }
+}
diff --git a/src/pulsecore/proplist-util.h b/src/pulsecore/proplist-util.h
new file mode 100644
index 00000000..c6bdc103
--- /dev/null
+++ b/src/pulsecore/proplist-util.h
@@ -0,0 +1,29 @@
+#ifndef fooproplistutilutilhfoo
+#define fooproplistutilutilhfoo
+
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2008 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 <pulse/proplist.h>
+
+void pa_init_proplist(pa_proplist *p);
+
+#endif
diff --git a/src/pulsecore/props.c b/src/pulsecore/props.c
index cbf748df..23d432ec 100644
--- a/src/pulsecore/props.c
+++ b/src/pulsecore/props.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/props.h b/src/pulsecore/props.h
index 880325f6..95db229b 100644
--- a/src/pulsecore/props.h
+++ b/src/pulsecore/props.h
@@ -1,8 +1,6 @@
#ifndef foopropshfoo
#define foopropshfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/protocol-cli.c b/src/pulsecore/protocol-cli.c
index 2f797a14..30cb475d 100644
--- a/src/pulsecore/protocol-cli.c
+++ b/src/pulsecore/protocol-cli.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/protocol-cli.h b/src/pulsecore/protocol-cli.h
index 3870def3..8922ac62 100644
--- a/src/pulsecore/protocol-cli.h
+++ b/src/pulsecore/protocol-cli.h
@@ -1,8 +1,6 @@
#ifndef fooprotocolclihfoo
#define fooprotocolclihfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c
index 492dc9fa..db1b4305 100644
--- a/src/pulsecore/protocol-esound.c
+++ b/src/pulsecore/protocol-esound.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -1042,7 +1040,7 @@ static int do_read(connection *c) {
}
if (!c->playback.current_memblock) {
- pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, 0));
+ pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, (size_t) -1));
c->playback.memblock_index = 0;
space = pa_memblock_get_length(c->playback.current_memblock);
@@ -1275,6 +1273,8 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk
} else {
size_t m;
+ chunk->length = PA_MIN(length, chunk->length);
+
c->playback.underrun = FALSE;
pa_memblockq_drop(c->input_memblockq, chunk->length);
diff --git a/src/pulsecore/protocol-esound.h b/src/pulsecore/protocol-esound.h
index 868ef5d2..0c9447d3 100644
--- a/src/pulsecore/protocol-esound.h
+++ b/src/pulsecore/protocol-esound.h
@@ -1,8 +1,6 @@
#ifndef fooprotocolesoundhfoo
#define fooprotocolesoundhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c
index bc2e9af6..03990435 100644
--- a/src/pulsecore/protocol-http.c
+++ b/src/pulsecore/protocol-http.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/protocol-http.h b/src/pulsecore/protocol-http.h
index cf952476..e3372335 100644
--- a/src/pulsecore/protocol-http.h
+++ b/src/pulsecore/protocol-http.h
@@ -1,8 +1,6 @@
#ifndef fooprotocolhttphfoo
#define fooprotocolhttphfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 2adcdfc7..923a5665 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -132,7 +130,8 @@ typedef struct upload_stream {
struct connection {
pa_msgobject parent;
- pa_bool_t authorized;
+ pa_bool_t authorized:1;
+ pa_bool_t is_local:1;
uint32_t version;
pa_protocol_native *protocol;
pa_client *client;
@@ -485,7 +484,7 @@ static void fix_record_buffer_attr_pre(record_stream *s, pa_bool_t adjust_latenc
pa_usec_t fragsize_usec;
/* So, the user asked us to adjust the latency according to
- * the what the source can provide. Half the latency will be
+ * what the source can provide. Half the latency will be
* spent on the hw buffer, half of it in the async buffer
* queue we maintain for each client. */
@@ -499,7 +498,8 @@ static void fix_record_buffer_attr_pre(record_stream *s, pa_bool_t adjust_latenc
fragsize_usec = s->source_latency;
*fragsize = pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
- }
+ } else
+ s->source_latency = 0;
}
static void fix_record_buffer_attr_post(record_stream *s, uint32_t *maxlength, uint32_t *fragsize) {
@@ -533,7 +533,8 @@ static record_stream* record_stream_new(
uint32_t *fragsize,
pa_source_output_flags_t flags,
pa_proplist *p,
- pa_bool_t adjust_latency) {
+ pa_bool_t adjust_latency,
+ pa_sink_input *direct_on_input) {
record_stream *s;
pa_source_output *source_output;
@@ -553,6 +554,7 @@ static record_stream* record_stream_new(
data.module = c->protocol->module;
data.client = c->client;
data.source = source;
+ data.direct_on_input = direct_on_input;
pa_source_output_new_data_set_sample_spec(&data, ss);
pa_source_output_new_data_set_channel_map(&data, map);
if (peak_detect)
@@ -597,6 +599,11 @@ static record_stream* record_stream_new(
pa_idxset_put(c->record_streams, s, &s->index);
+ pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
+ ((double) pa_bytes_to_usec(s->fragment_size, &source_output->sample_spec) + (double) s->source_latency) / PA_USEC_PER_MSEC,
+ (double) pa_bytes_to_usec(s->fragment_size, &source_output->sample_spec) / PA_USEC_PER_MSEC,
+ (double) s->source_latency / PA_USEC_PER_MSEC);
+
pa_source_output_put(s->source_output);
return s;
}
@@ -803,7 +810,7 @@ static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_la
if (*tlength <= *minreq)
*tlength = *minreq*2 + frame_size;
- if (*prebuf <= 0)
+ if (*prebuf <= 0 || *prebuf > *tlength)
*prebuf = *tlength;
}
@@ -1281,7 +1288,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
if (pa_memblockq_peek(s->memblockq, chunk) < 0) {
-/* pa_log("UNDERRUN: %lu", pa_memblockq_get_length(s->memblockq)); */
+/* pa_log("UNDERRUN: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
s->drain_request = FALSE;
@@ -1298,6 +1305,8 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
/* pa_log("NOTUNDERRUN %lu", (unsigned long) chunk->length); */
+ chunk->length = PA_MIN(nbytes, chunk->length);
+
if (i->thread_info.underrun_for > 0)
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
@@ -1750,7 +1759,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
record_stream *s;
uint32_t maxlength, fragment_size;
uint32_t source_index;
- const char *name, *source_name;
+ const char *name = NULL, *source_name;
pa_sample_spec ss;
pa_channel_map map;
pa_tagstruct *reply;
@@ -1768,6 +1777,8 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
peak_detect = FALSE;
pa_source_output_flags_t flags = 0;
pa_proplist *p;
+ uint32_t direct_on_input_idx = PA_INVALID_INDEX;
+ pa_sink_input *direct_on_input = NULL;
connection_assert_ref(c);
pa_assert(t);
@@ -1816,7 +1827,8 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
- pa_tagstruct_get_proplist(t, p) < 0) {
+ pa_tagstruct_get_proplist(t, p) < 0 ||
+ pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
protocol_error(c);
pa_proplist_free(p);
return;
@@ -1846,6 +1858,15 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
}
}
+ if (direct_on_input_idx != PA_INVALID_INDEX) {
+
+ if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
+ pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
+ pa_proplist_free(p);
+ return;
+ }
+ }
+
flags =
(corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
(no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
@@ -1856,7 +1877,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
(no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
(variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0);
- s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency);
+ s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input);
pa_proplist_free(p);
CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
@@ -1914,7 +1935,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t
connection *c = CONNECTION(userdata);
const void*cookie;
pa_tagstruct *reply;
- char tmp[16];
+ pa_bool_t shm_on_remote, do_shm;
connection_assert_ref(c);
pa_assert(t);
@@ -1932,8 +1953,17 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t
return;
}
- pa_snprintf(tmp, sizeof(tmp), "%u", c->version);
- pa_proplist_sets(c->client->proplist, "native-protocol.version", tmp);
+ /* Starting with protocol version 13 the MSB of the version tag
+ reflects if shm is available for this connection or
+ not. */
+ if (c->version >= 13) {
+ shm_on_remote = !!(c->version & 0x80000000U);
+ c->version &= 0x7FFFFFFFU;
+ }
+
+ pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
+
+ pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
if (!c->authorized) {
pa_bool_t success = FALSE;
@@ -1964,16 +1994,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t
pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
(unsigned long) creds->uid,
(unsigned long) creds->gid,
- success);
-
- if (c->version >= 10 &&
- pa_mempool_is_shared(c->protocol->core->mempool) &&
- creds->uid == getuid()) {
-
- pa_pstream_enable_shm(c->pstream, TRUE);
- pa_log_info("Enabled SHM for new connection");
- }
-
+ (int) success);
}
#endif
@@ -1993,8 +2014,32 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t
}
}
+ /* Enable shared memory support if possible */
+ do_shm =
+ pa_mempool_is_shared(c->protocol->core->mempool) &&
+ c->is_local;
+
+ pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
+
+ if (do_shm)
+ if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
+ do_shm = FALSE;
+
+ if (do_shm) {
+ /* Only enable SHM if both sides are owned by the same
+ * user. This is a security measure because otherwise data
+ * private to the user might leak. */
+
+ const pa_creds *creds;
+ if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
+ do_shm = FALSE;
+ }
+
+ pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
+ pa_pstream_enable_shm(c->pstream, do_shm);
+
reply = reply_new(tag);
- pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION);
+ pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
#ifdef HAVE_CREDS
{
@@ -2229,7 +2274,7 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
connection_assert_ref(c);
pa_assert(t);
- if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
+ if (pa_tagstruct_gets(t, &name) < 0 ||
pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
pa_tagstruct_get_channel_map(t, &map) < 0 ||
pa_tagstruct_getu32(t, &length) < 0) {
@@ -2244,9 +2289,6 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
- if (c->version < 13)
- CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
-
p = pa_proplist_new();
if (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) {
@@ -2257,6 +2299,11 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
if (c->version < 13)
pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
+ else if (!name)
+ if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
+ name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
+
+ CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
s = upload_stream_new(c, &ss, &map, name, length, p);
pa_proplist_free(p);
@@ -2488,6 +2535,7 @@ static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) {
static void sink_input_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink_input *s) {
pa_sample_spec fixed_ss;
+ pa_usec_t sink_latency;
pa_assert(t);
pa_sink_input_assert_ref(s);
@@ -2502,8 +2550,8 @@ static void sink_input_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink_in
pa_tagstruct_put_sample_spec(t, &fixed_ss);
pa_tagstruct_put_channel_map(t, &s->channel_map);
pa_tagstruct_put_cvolume(t, &s->volume);
- pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s));
- pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink));
+ 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)));
pa_tagstruct_puts(t, s->driver);
if (c->version >= 11)
@@ -2514,6 +2562,7 @@ static void sink_input_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink_in
static void source_output_fill_tagstruct(connection *c, pa_tagstruct *t, pa_source_output *s) {
pa_sample_spec fixed_ss;
+ pa_usec_t source_latency;
pa_assert(t);
pa_source_output_assert_ref(s);
@@ -2527,8 +2576,8 @@ static void source_output_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sour
pa_tagstruct_putu32(t, s->source->index);
pa_tagstruct_put_sample_spec(t, &fixed_ss);
pa_tagstruct_put_channel_map(t, &s->channel_map);
- pa_tagstruct_put_usec(t, pa_source_output_get_latency(s));
- pa_tagstruct_put_usec(t, pa_source_get_latency(s->source));
+ pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
+ pa_tagstruct_put_usec(t, source_latency);
pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
pa_tagstruct_puts(t, s->driver);
@@ -2542,12 +2591,15 @@ static void scache_fill_tagstruct(connection *c, pa_tagstruct *t, pa_scache_entr
pa_assert(t);
pa_assert(e);
- fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
+ if (e->memchunk.memblock)
+ fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
+ else
+ memset(&fixed_ss, 0, sizeof(fixed_ss));
pa_tagstruct_putu32(t, e->index);
pa_tagstruct_puts(t, e->name);
pa_tagstruct_put_cvolume(t, &e->volume);
- pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec));
+ pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
pa_tagstruct_put_sample_spec(t, &fixed_ss);
pa_tagstruct_put_channel_map(t, &e->channel_map);
pa_tagstruct_putu32(t, e->memchunk.length);
@@ -3885,7 +3937,6 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo
connection *c;
char cname[256], pname[128];
- pa_assert(s);
pa_assert(io);
pa_assert(p);
@@ -3914,6 +3965,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo
} else
c->auth_timeout_event = NULL;
+ c->is_local = pa_iochannel_socket_is_local(io);
c->version = 8;
c->protocol = p;
pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
@@ -3946,7 +3998,6 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo
#ifdef HAVE_CREDS
if (pa_iochannel_creds_supported(io))
pa_iochannel_creds_enable(io);
-
#endif
}
@@ -4005,7 +4056,7 @@ static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_mo
pa_log("auth-group-enabled= expects a boolean argument.");
return NULL;
}
- p->auth_group = a ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", c->is_system_instance ? PA_ACCESS_GROUP : NULL)) : NULL;
+ p->auth_group = a ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
if (p->auth_group)
pa_log_info("Allowing access to group '%s'.", p->auth_group);
diff --git a/src/pulsecore/protocol-native.h b/src/pulsecore/protocol-native.h
index bf05f937..a52fa8cf 100644
--- a/src/pulsecore/protocol-native.h
+++ b/src/pulsecore/protocol-native.h
@@ -1,8 +1,6 @@
#ifndef fooprotocolnativehfoo
#define fooprotocolnativehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c
index cbe48440..020a281d 100644
--- a/src/pulsecore/protocol-simple.c
+++ b/src/pulsecore/protocol-simple.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -374,6 +372,8 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk
} else {
size_t m;
+ chunk->length = PA_MIN(length, chunk->length);
+
c->playback.underrun = FALSE;
pa_memblockq_drop(c->input_memblockq, chunk->length);
diff --git a/src/pulsecore/protocol-simple.h b/src/pulsecore/protocol-simple.h
index 3b02c88e..e1b3143b 100644
--- a/src/pulsecore/protocol-simple.h
+++ b/src/pulsecore/protocol-simple.h
@@ -1,8 +1,6 @@
#ifndef fooprotocolsimplehfoo
#define fooprotocolsimplehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/pstream-util.c b/src/pulsecore/pstream-util.c
index a6932158..f84f486a 100644
--- a/src/pulsecore/pstream-util.c
+++ b/src/pulsecore/pstream-util.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/pstream-util.h b/src/pulsecore/pstream-util.h
index 67759f2a..ae0d79c3 100644
--- a/src/pulsecore/pstream-util.h
+++ b/src/pulsecore/pstream-util.h
@@ -1,8 +1,6 @@
#ifndef foopstreamutilhfoo
#define foopstreamutilhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c
index 5004d67f..e26ca473 100644
--- a/src/pulsecore/pstream.c
+++ b/src/pulsecore/pstream.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h
index 00b37b71..a528b25c 100644
--- a/src/pulsecore/pstream.h
+++ b/src/pulsecore/pstream.h
@@ -1,8 +1,6 @@
#ifndef foopstreamhfoo
#define foopstreamhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/queue.c b/src/pulsecore/queue.c
index 9b6a37f0..08fd1426 100644
--- a/src/pulsecore/queue.c
+++ b/src/pulsecore/queue.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/queue.h b/src/pulsecore/queue.h
index cd767364..b09216cf 100644
--- a/src/pulsecore/queue.h
+++ b/src/pulsecore/queue.h
@@ -1,8 +1,6 @@
#ifndef fooqueuehfoo
#define fooqueuehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/random.c b/src/pulsecore/random.c
index 87afebfa..5deac37b 100644
--- a/src/pulsecore/random.c
+++ b/src/pulsecore/random.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -64,7 +62,11 @@ static int random_proper(void *ret_data, size_t length) {
while (*device) {
ret = 0;
- if ((fd = open(*device, O_RDONLY)) >= 0) {
+ if ((fd = open(*device, O_RDONLY
+#ifdef O_NOCTTY
+ | O_NOCTTY
+#endif
+ )) >= 0) {
if ((r = pa_loop_read(fd, ret_data, length, NULL)) < 0 || (size_t) r != length)
ret = -1;
diff --git a/src/pulsecore/random.h b/src/pulsecore/random.h
index 01b7d746..36d7f9df 100644
--- a/src/pulsecore/random.h
+++ b/src/pulsecore/random.h
@@ -1,8 +1,6 @@
#ifndef foorandomhfoo
#define foorandomhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/refcnt.h b/src/pulsecore/refcnt.h
index f0885fb4..291f4504 100644
--- a/src/pulsecore/refcnt.h
+++ b/src/pulsecore/refcnt.h
@@ -1,8 +1,6 @@
#ifndef foopulserefcnthfoo
#define foopulserefcnthfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index d645639c..00dc794c 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -1457,10 +1455,10 @@ static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned i
r->peaks.max_i[c] = n;
}
- for (c = 0; c < r->o_ss.channels; c++, d++)
+ for (c = 0; c < r->o_ss.channels; c++, d++) {
*d = r->peaks.max_i[c];
-
- memset(r->peaks.max_i, 0, sizeof(r->peaks.max_i));
+ r->peaks.max_i[c] = 0;
+ }
} else {
unsigned i, c;
float *s = (float*) ((uint8_t*) src + fz * j);
@@ -1476,11 +1474,13 @@ static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned i
r->peaks.max_f[c] = n;
}
- for (c = 0; c < r->o_ss.channels; c++, d++)
+ for (c = 0; c < r->o_ss.channels; c++, d++) {
*d = r->peaks.max_f[c];
-
- memset(r->peaks.max_f, 0, sizeof(r->peaks.max_f));
+ r->peaks.max_f[c] = 0;
+ }
}
+
+ start = j+1;
}
pa_memblock_release(input->memblock);
diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h
index 8534f5b5..5e302a9b 100644
--- a/src/pulsecore/resampler.h
+++ b/src/pulsecore/resampler.h
@@ -1,8 +1,6 @@
#ifndef fooresamplerhfoo
#define fooresamplerhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/rtclock.c b/src/pulsecore/rtclock.c
index e74e5243..f33de830 100644
--- a/src/pulsecore/rtclock.c
+++ b/src/pulsecore/rtclock.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/rtclock.h b/src/pulsecore/rtclock.h
index f68ad761..705de48f 100644
--- a/src/pulsecore/rtclock.h
+++ b/src/pulsecore/rtclock.h
@@ -1,8 +1,6 @@
#ifndef foopulsertclockhfoo
#define foopulsertclockhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/rtpoll.c b/src/pulsecore/rtpoll.c
index 64fa42ad..a67a5516 100644
--- a/src/pulsecore/rtpoll.c
+++ b/src/pulsecore/rtpoll.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -514,6 +512,9 @@ void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, pa_usec_t usec) {
void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) {
pa_assert(p);
+ /* Scheduling a timeout for more than an hour is very very suspicious */
+ pa_assert(usec <= PA_USEC_PER_SEC*60ULL*60ULL);
+
pa_rtclock_get(&p->next_elapse);
pa_timeval_add(&p->next_elapse, usec);
p->timer_enabled = TRUE;
diff --git a/src/pulsecore/rtpoll.h b/src/pulsecore/rtpoll.h
index 16dadbc3..08776ef0 100644
--- a/src/pulsecore/rtpoll.h
+++ b/src/pulsecore/rtpoll.h
@@ -1,8 +1,6 @@
#ifndef foopulsertpollhfoo
#define foopulsertpollhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/rtsig.c b/src/pulsecore/rtsig.c
index bfc49c88..4df217c3 100644
--- a/src/pulsecore/rtsig.c
+++ b/src/pulsecore/rtsig.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/rtsig.h b/src/pulsecore/rtsig.h
index 7830d272..e414122d 100644
--- a/src/pulsecore/rtsig.h
+++ b/src/pulsecore/rtsig.h
@@ -1,8 +1,6 @@
#ifndef foopulsertsighfoo
#define foopulsertsighfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c
index a8028296..b42b79d1 100644
--- a/src/pulsecore/sample-util.c
+++ b/src/pulsecore/sample-util.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h
index 59b4c632..cef70750 100644
--- a/src/pulsecore/sample-util.h
+++ b/src/pulsecore/sample-util.h
@@ -1,8 +1,6 @@
#ifndef foosampleutilhfoo
#define foosampleutilhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/sconv-s16be.c b/src/pulsecore/sconv-s16be.c
index 638beb2e..e7e1449a 100644
--- a/src/pulsecore/sconv-s16be.c
+++ b/src/pulsecore/sconv-s16be.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/sconv-s16be.h b/src/pulsecore/sconv-s16be.h
index 454c9508..60580815 100644
--- a/src/pulsecore/sconv-s16be.h
+++ b/src/pulsecore/sconv-s16be.h
@@ -1,8 +1,6 @@
#ifndef foosconv_s16befoo
#define foosconv_s16befoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c
index 90e9b6d2..41670f27 100644
--- a/src/pulsecore/sconv-s16le.c
+++ b/src/pulsecore/sconv-s16le.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/sconv-s16le.h b/src/pulsecore/sconv-s16le.h
index 4165f8a2..8d4c87c3 100644
--- a/src/pulsecore/sconv-s16le.h
+++ b/src/pulsecore/sconv-s16le.h
@@ -1,8 +1,6 @@
#ifndef foosconv_s16lefoo
#define foosconv_s16lefoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c
index ebd74586..581e4681 100644
--- a/src/pulsecore/sconv.c
+++ b/src/pulsecore/sconv.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/sconv.h b/src/pulsecore/sconv.h
index 901f50a3..59710369 100644
--- a/src/pulsecore/sconv.h
+++ b/src/pulsecore/sconv.h
@@ -1,8 +1,6 @@
#ifndef foosconvhfoo
#define foosconvhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/semaphore-posix.c b/src/pulsecore/semaphore-posix.c
index 750c2afc..7c9f859d 100644
--- a/src/pulsecore/semaphore-posix.c
+++ b/src/pulsecore/semaphore-posix.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/semaphore-win32.c b/src/pulsecore/semaphore-win32.c
index f6576348..41e0b8d4 100644
--- a/src/pulsecore/semaphore-win32.c
+++ b/src/pulsecore/semaphore-win32.c
@@ -1,5 +1,3 @@
-/* $Id: mutex-win32.c 1426 2007-02-13 15:35:19Z ossman $ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/semaphore.h b/src/pulsecore/semaphore.h
index c394e0f2..850ae817 100644
--- a/src/pulsecore/semaphore.h
+++ b/src/pulsecore/semaphore.h
@@ -1,8 +1,6 @@
#ifndef foopulsesemaphorehfoo
#define foopulsesemaphorehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c
index a6843819..298bf716 100644
--- a/src/pulsecore/shm.c
+++ b/src/pulsecore/shm.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/shm.h b/src/pulsecore/shm.h
index 60bc355f..c2adbd07 100644
--- a/src/pulsecore/shm.h
+++ b/src/pulsecore/shm.h
@@ -1,8 +1,6 @@
#ifndef foopulseshmhfoo
#define foopulseshmhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/shmasyncq.c b/src/pulsecore/shmasyncq.c
index 7af2985c..eac56adb 100644
--- a/src/pulsecore/shmasyncq.c
+++ b/src/pulsecore/shmasyncq.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/shmasyncq.h b/src/pulsecore/shmasyncq.h
index ca35ffd2..9845c391 100644
--- a/src/pulsecore/shmasyncq.h
+++ b/src/pulsecore/shmasyncq.h
@@ -1,8 +1,6 @@
#ifndef foopulseshmasyncqhfoo
#define foopulseshmasyncqhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index d51ff810..43e7bb21 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -44,7 +42,6 @@
#define MEMBLOCKQ_MAXLENGTH (32*1024*1024)
#define CONVERT_BUFFER_LENGTH (PA_PAGE_SIZE)
-#define MOVE_BUFFER_LENGTH (PA_PAGE_SIZE*256)
static PA_DEFINE_CHECK_TYPE(pa_sink_input, pa_msgobject);
@@ -94,12 +91,16 @@ void pa_sink_input_new_data_done(pa_sink_input_new_data *data) {
pa_proplist_free(data->proplist);
}
+/* Called from main context */
static void reset_callbacks(pa_sink_input *i) {
pa_assert(i);
i->pop = NULL;
i->process_rewind = NULL;
i->update_max_rewind = NULL;
+ i->update_max_request = NULL;
+ i->update_sink_requested_latency = NULL;
+ i->update_sink_latency_range = NULL;
i->attach = NULL;
i->detach = NULL;
i->suspend = NULL;
@@ -109,6 +110,7 @@ static void reset_callbacks(pa_sink_input *i) {
i->state_change = NULL;
}
+/* Called from main context */
pa_sink_input* pa_sink_input_new(
pa_core *core,
pa_sink_input_new_data *data,
@@ -127,7 +129,7 @@ pa_sink_input* pa_sink_input_new(
pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
if (!data->sink)
- data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK, 1);
+ data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK, TRUE);
pa_return_null_if_fail(data->sink);
pa_return_null_if_fail(pa_sink_get_state(data->sink) != PA_SINK_UNLINKED);
@@ -237,6 +239,8 @@ pa_sink_input* pa_sink_input_new(
} else
i->sync_next = i->sync_prev = NULL;
+ i->direct_outputs = pa_idxset_new(NULL, NULL);
+
reset_callbacks(i);
i->userdata = NULL;
@@ -252,6 +256,7 @@ pa_sink_input* pa_sink_input_new(
i->thread_info.rewrite_flush = FALSE;
i->thread_info.underrun_for = (uint64_t) -1;
i->thread_info.playing_for = 0;
+ i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
i->thread_info.render_memblockq = pa_memblockq_new(
0,
@@ -278,6 +283,7 @@ pa_sink_input* pa_sink_input_new(
return i;
}
+/* Called from main context */
static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) {
pa_assert(i);
@@ -289,6 +295,7 @@ static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) {
pa_sink_update_status(i->sink);
}
+/* Called from main context */
static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) {
pa_sink_input *ssync;
pa_assert(i);
@@ -299,8 +306,7 @@ static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) {
if (i->state == state)
return 0;
- if (pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0)
- return -1;
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
update_n_corked(i, state);
i->state = state;
@@ -314,14 +320,23 @@ static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) {
ssync->state = state;
}
- if (state != PA_SINK_INPUT_UNLINKED)
+ if (state != PA_SINK_INPUT_UNLINKED) {
pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], i);
+ for (ssync = i->sync_prev; ssync; ssync = ssync->sync_prev)
+ pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], ssync);
+
+ for (ssync = i->sync_next; ssync; ssync = ssync->sync_next)
+ pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], ssync);
+ }
+
return 0;
}
+/* Called from main context */
void pa_sink_input_unlink(pa_sink_input *i) {
pa_bool_t linked;
+ pa_source_output *o, *p = NULL;
pa_assert(i);
/* See pa_sink_unlink() for a couple of comments how this function
@@ -345,12 +360,18 @@ void pa_sink_input_unlink(pa_sink_input *i) {
if (pa_idxset_remove_by_data(i->sink->inputs, i, NULL))
pa_sink_input_unref(i);
+ while ((o = pa_idxset_first(i->direct_outputs, NULL))) {
+ pa_assert(o != p);
+ pa_source_output_kill(o);
+ p = o;
+ }
+
update_n_corked(i, PA_SINK_INPUT_UNLINKED);
i->state = PA_SINK_INPUT_UNLINKED;
if (linked)
if (i->sink->asyncmsgq)
- pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL) == 0);
reset_callbacks(i);
@@ -363,6 +384,7 @@ void pa_sink_input_unlink(pa_sink_input *i) {
pa_sink_input_unref(i);
}
+/* Called from main context */
static void sink_input_free(pa_object *o) {
pa_sink_input* i = PA_SINK_INPUT(o);
@@ -385,17 +407,27 @@ static void sink_input_free(pa_object *o) {
if (i->proplist)
pa_proplist_free(i->proplist);
+ if (i->direct_outputs)
+ pa_idxset_free(i->direct_outputs, NULL, NULL);
+
+ if (i->thread_info.direct_outputs)
+ pa_hashmap_free(i->thread_info.direct_outputs, NULL, NULL);
+
pa_xfree(i->driver);
pa_xfree(i);
}
+/* Called from main context */
void pa_sink_input_put(pa_sink_input *i) {
pa_sink_input_state_t state;
pa_sink_input_assert_ref(i);
pa_assert(i->state == PA_SINK_INPUT_INIT);
+
+ /* The following fields must be initialized properly */
pa_assert(i->pop);
pa_assert(i->process_rewind);
+ pa_assert(i->kill);
i->thread_info.volume = i->volume;
i->thread_info.muted = i->muted;
@@ -405,33 +437,36 @@ void pa_sink_input_put(pa_sink_input *i) {
update_n_corked(i, state);
i->state = state;
- pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL) == 0);
pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index);
pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], i);
}
+/* Called from main context */
void pa_sink_input_kill(pa_sink_input*i) {
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
- if (i->kill)
- i->kill(i);
+ i->kill(i);
}
-pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) {
- pa_usec_t r = 0;
+/* Called from main context */
+pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) {
+ pa_usec_t r[2] = { 0, 0 };
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
- if (pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, &r, 0, NULL) < 0)
- r = 0;
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0);
if (i->get_latency)
- r += i->get_latency(i);
+ r[0] += i->get_latency(i);
+
+ if (sink_latency)
+ *sink_latency = r[1];
- return r;
+ return r[0];
}
/* Called from thread context */
@@ -684,42 +719,54 @@ void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes /* in the
i->update_max_rewind(i, i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, nbytes) : nbytes);
}
+/* Called from thread context */
+void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */) {
+ pa_sink_input_assert_ref(i);
+ pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
+ pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
+
+ if (i->update_max_request)
+ i->update_max_request(i, i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, nbytes) : nbytes);
+}
+
+/* Called from thread context */
static pa_usec_t fixup_latency(pa_sink *s, pa_usec_t usec) {
pa_sink_assert_ref(s);
if (usec == (pa_usec_t) -1)
return usec;
- if (s->max_latency > 0 && usec > s->max_latency)
- usec = s->max_latency;
+ if (s->thread_info.max_latency > 0 && usec > s->thread_info.max_latency)
+ usec = s->thread_info.max_latency;
- if (s->min_latency > 0 && usec < s->min_latency)
- usec = s->min_latency;
+ if (s->thread_info.min_latency > 0 && usec < s->thread_info.min_latency)
+ usec = s->thread_info.min_latency;
return usec;
}
+/* Called from thread context */
pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa_usec_t usec) {
pa_sink_input_assert_ref(i);
usec = fixup_latency(i->sink, usec);
-
i->thread_info.requested_sink_latency = usec;
pa_sink_invalidate_requested_latency(i->sink);
return usec;
}
+/* Called from main context */
pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) {
pa_sink_input_assert_ref(i);
- usec = fixup_latency(i->sink, usec);
-
if (PA_SINK_INPUT_IS_LINKED(i->state))
- pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL);
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
else {
/* If this sink input is not realized yet, we have to touch
* the thread info data directly */
+
+ usec = fixup_latency(i->sink, usec);
i->thread_info.requested_sink_latency = usec;
i->sink->thread_info.requested_latency_valid = FALSE;
}
@@ -727,13 +774,14 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec)
return usec;
}
+/* Called from main context */
pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) {
pa_usec_t usec = 0;
pa_sink_input_assert_ref(i);
if (PA_SINK_INPUT_IS_LINKED(i->state))
- pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
else
/* If this sink input is not realized yet, we have to touch
* the thread info data directly */
@@ -742,19 +790,22 @@ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) {
return usec;
}
+/* Called from main context */
void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) {
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
+ pa_assert(volume);
if (pa_cvolume_equal(&i->volume, volume))
return;
i->volume = *volume;
- pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, NULL, pa_xfree);
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, &i->volume, 0, NULL) == 0);
pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
}
+/* Called from main context */
const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) {
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
@@ -762,6 +813,7 @@ const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) {
return &i->volume;
}
+/* Called from main context */
void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute) {
pa_assert(i);
pa_sink_input_assert_ref(i);
@@ -776,13 +828,15 @@ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute) {
pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
}
-int pa_sink_input_get_mute(pa_sink_input *i) {
+/* Called from main context */
+pa_bool_t pa_sink_input_get_mute(pa_sink_input *i) {
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
- return !!i->muted;
+ return i->muted;
}
+/* Called from main context */
void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) {
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
@@ -790,6 +844,7 @@ void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) {
sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING);
}
+/* Called from main context */
int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
@@ -806,6 +861,7 @@ int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
return 0;
}
+/* Called from main context */
void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
const char *old;
pa_sink_input_assert_ref(i);
@@ -829,16 +885,19 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
}
}
+/* Called from main context */
pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
pa_sink_input_assert_ref(i);
return i->resample_method;
}
+/* Called from main context */
int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) {
pa_resampler *new_resampler;
pa_sink *origin;
pa_sink_input_move_hook_data hook_data;
+ pa_source_output *o, *p = NULL;
pa_sink_input_assert_ref(i);
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
@@ -862,6 +921,13 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) {
return -1;
}
+ /* Kill directly connected outputs */
+ while ((o = pa_idxset_first(i->direct_outputs, NULL))) {
+ pa_assert(o != p);
+ pa_source_output_kill(o);
+ p = o;
+ }
+
if (i->thread_info.resampler &&
pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) &&
pa_channel_map_equal(&origin->channel_map, &dest->channel_map))
@@ -893,7 +959,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) {
hook_data.destination = dest;
pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], &hook_data);
- pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0);
pa_idxset_remove_by_data(origin->inputs, i, NULL);
pa_idxset_put(dest->inputs, i, NULL);
@@ -927,7 +993,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) {
pa_sink_update_status(origin);
pa_sink_update_status(dest);
- pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0);
if (i->moved)
i->moved(i);
@@ -942,6 +1008,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) {
return 0;
}
+/* Called from IO thread context */
void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state_t state) {
pa_sink_input_assert_ref(i);
@@ -971,14 +1038,13 @@ void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state
i->thread_info.state = state;
}
-/* Called from thread context */
+/* Called from thread context, except when it is not. */
int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
pa_sink_input *i = PA_SINK_INPUT(o);
-
pa_sink_input_assert_ref(i);
- pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
switch (code) {
+
case PA_SINK_INPUT_MESSAGE_SET_VOLUME:
i->thread_info.volume = *((pa_cvolume*) userdata);
pa_sink_input_request_rewind(i, 0, TRUE, FALSE);
@@ -991,8 +1057,13 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
pa_usec_t *r = userdata;
+ pa_usec_t sink_usec = 0;
+
+ r[0] += pa_bytes_to_usec(pa_memblockq_get_length(i->thread_info.render_memblockq), &i->sink->sample_spec);
+
+ if (i->sink->parent.process_msg(PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_GET_LATENCY, &sink_usec, 0, NULL) >= 0)
+ r[1] += sink_usec;
- *r += pa_bytes_to_usec(pa_memblockq_get_length(i->thread_info.render_memblockq), &i->sink->sample_spec);
return 0;
}
@@ -1017,10 +1088,12 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
return 0;
}
- case PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY:
+ case PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY: {
+ pa_usec_t *usec = userdata;
- pa_sink_input_set_requested_latency_within_thread(i, (pa_usec_t) offset);
+ *usec = pa_sink_input_set_requested_latency_within_thread(i, *usec);
return 0;
+ }
case PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY: {
pa_usec_t *r = userdata;
@@ -1033,6 +1106,7 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
return -1;
}
+/* Called from main thread */
pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i) {
pa_sink_input_assert_ref(i);
@@ -1052,6 +1126,7 @@ pa_bool_t pa_sink_input_safe_to_remove(pa_sink_input *i) {
return TRUE;
}
+/* Called from IO context */
void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sample spec */, pa_bool_t rewrite, pa_bool_t flush) {
size_t lbq;
@@ -1111,6 +1186,7 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam
pa_sink_request_rewind(i->sink, nbytes - lbq);
}
+/* Called from main context */
pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret) {
pa_sink_input_assert_ref(i);
pa_assert(ret);
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 5f146122..c07a7404 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -1,8 +1,6 @@
#ifndef foopulsesinkinputhfoo
#define foopulsesinkinputhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -73,13 +71,19 @@ struct pa_sink_input {
pa_sink_input_state_t state;
pa_sink_input_flags_t flags;
- pa_proplist *proplist;
char *driver; /* may be NULL */
+ pa_proplist *proplist;
+
pa_module *module; /* may be NULL */
pa_client *client; /* may be NULL */
pa_sink *sink;
+ /* A sink input may be connected to multiple source outputs
+ * directly, so that they don't get mixed data of the entire
+ * source. */
+ pa_idxset *direct_outputs;
+
pa_sample_spec sample_spec;
pa_channel_map channel_map;
@@ -109,6 +113,18 @@ struct pa_sink_input {
* changes. Called from IO context. */
void (*update_max_rewind) (pa_sink_input *i, size_t nbytes); /* may be NULL */
+ /* Called whenever the maxiumum request size of the sink
+ * changes. Called from IO context. */
+ void (*update_max_request) (pa_sink_input *i, size_t nbytes); /* may be NULL */
+
+ /* Called whenever the configured latency of the sink
+ * changes. Called from IO context. */
+ void (*update_sink_requested_latency) (pa_sink_input *i); /* may be NULL */
+
+ /* Called whenver the latency range of the sink changes. Called
+ * from IO context. */
+ void (*update_sink_latency_range) (pa_sink_input *i); /* may be NULL */
+
/* If non-NULL this function is called when the input is first
* connected to a sink or when the rtpoll/asyncmsgq fields
* change. You usually don't need to implement this function
@@ -130,12 +146,12 @@ struct pa_sink_input {
/* Supposed to unlink and destroy this stream. Called from main
* context. */
- void (*kill) (pa_sink_input *i); /* may be NULL */
+ void (*kill) (pa_sink_input *i); /* may NOT be NULL */
/* Return the current latency (i.e. length of bufferd audio) of
- this stream. Called from main context. If NULL a
- PA_SINK_INPUT_MESSAGE_GET_LATENCY message is sent to the IO thread
- instead. */
+ this stream. Called from main context. This is added to what the
+ PA_SINK_INPUT_MESSAGE_GET_LATENCY message sent to the IO thread
+ returns */
pa_usec_t (*get_latency) (pa_sink_input *i); /* may be NULL */
/* If non_NULL this function is called from thread context if the
@@ -166,6 +182,8 @@ struct pa_sink_input {
/* The requested latency for the sink */
pa_usec_t requested_sink_latency;
+
+ pa_hashmap *direct_outputs;
} thread_info;
void *userdata;
@@ -253,12 +271,12 @@ int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate);
/* External code may request disconnection with this function */
void pa_sink_input_kill(pa_sink_input*i);
-pa_usec_t pa_sink_input_get_latency(pa_sink_input *i);
+pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency);
void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume);
const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i);
void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute);
-int pa_sink_input_get_mute(pa_sink_input *i);
+pa_bool_t pa_sink_input_get_mute(pa_sink_input *i);
pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i);
@@ -274,6 +292,7 @@ int pa_sink_input_peek(pa_sink_input *i, size_t length, pa_memchunk *chunk, pa_c
void pa_sink_input_drop(pa_sink_input *i, size_t length);
void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */);
void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */);
+void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */);
void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state_t state);
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 31c3cfc8..edb023b2 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -105,6 +103,7 @@ void pa_sink_new_data_done(pa_sink_new_data *data) {
pa_proplist_free(data->proplist);
}
+/* Called from main context */
static void reset_callbacks(pa_sink *s) {
pa_assert(s);
@@ -117,6 +116,7 @@ static void reset_callbacks(pa_sink *s) {
s->update_requested_latency = NULL;
}
+/* Called from main context */
pa_sink* pa_sink_new(
pa_core *core,
pa_sink_new_data *data,
@@ -192,7 +192,7 @@ pa_sink* pa_sink_new(
s->volume = data->volume;
s->muted = data->muted;
- s->refresh_volume = s->refresh_mute = FALSE;
+ s->refresh_volume = s->refresh_muted = FALSE;
reset_callbacks(s);
s->userdata = NULL;
@@ -207,17 +207,17 @@ pa_sink* pa_sink_new(
&s->sample_spec,
0);
- s->min_latency = DEFAULT_MIN_LATENCY;
- s->max_latency = s->min_latency;
-
s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
- s->thread_info.soft_volume = s->volume;
- s->thread_info.soft_muted = s->muted;
+ pa_cvolume_reset(&s->thread_info.soft_volume, s->sample_spec.channels);
+ s->thread_info.soft_muted = FALSE;
s->thread_info.state = s->state;
s->thread_info.rewind_nbytes = 0;
s->thread_info.max_rewind = 0;
+ s->thread_info.max_request = 0;
s->thread_info.requested_latency_valid = FALSE;
s->thread_info.requested_latency = 0;
+ s->thread_info.min_latency = DEFAULT_MIN_LATENCY;
+ s->thread_info.max_latency = 0;
pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
@@ -249,11 +249,14 @@ pa_sink* pa_sink_new(
}
s->monitor_source->monitor_of = s;
+
+ pa_source_set_latency_range(s->monitor_source, s->thread_info.min_latency, s->thread_info.max_latency);
pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
return s;
}
+/* Called from main context */
static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
int ret;
pa_bool_t suspend_change;
@@ -272,8 +275,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
return -1;
if (s->asyncmsgq)
- if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0)
- return -1;
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
s->state = state;
@@ -294,18 +296,25 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
return 0;
}
+/* Called from main context */
void pa_sink_put(pa_sink* s) {
pa_sink_assert_ref(s);
pa_assert(s->state == PA_SINK_INIT);
+
+ /* The following fields must be initialized properly when calling _put() */
pa_assert(s->asyncmsgq);
pa_assert(s->rtpoll);
+ pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency ||
+ s->thread_info.min_latency <= s->thread_info.max_latency);
- pa_assert(!s->min_latency || !s->max_latency || s->min_latency <= s->max_latency);
-
- if (!(s->flags & PA_SINK_HW_VOLUME_CTRL))
+ if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) {
s->flags |= PA_SINK_DECIBEL_VOLUME;
+ s->thread_info.soft_volume = s->volume;
+ s->thread_info.soft_muted = s->muted;
+ }
+
pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
pa_source_put(s->monitor_source);
@@ -314,6 +323,7 @@ void pa_sink_put(pa_sink* s) {
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
}
+/* Called from main context */
void pa_sink_unlink(pa_sink* s) {
pa_bool_t linked;
pa_sink_input *i, *j = NULL;
@@ -359,6 +369,7 @@ void pa_sink_unlink(pa_sink* s) {
}
}
+/* Called from main context */
static void sink_free(pa_object *o) {
pa_sink *s = PA_SINK(o);
pa_sink_input *i;
@@ -395,6 +406,7 @@ static void sink_free(pa_object *o) {
pa_xfree(s);
}
+/* Called from main context */
void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
pa_sink_assert_ref(s);
@@ -404,6 +416,7 @@ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
pa_source_set_asyncmsgq(s->monitor_source, q);
}
+/* Called from main context */
void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
pa_sink_assert_ref(s);
@@ -412,6 +425,7 @@ void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
pa_source_set_rtpoll(s->monitor_source, p);
}
+/* Called from main context */
int pa_sink_update_status(pa_sink*s) {
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
@@ -422,6 +436,7 @@ int pa_sink_update_status(pa_sink*s) {
return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
}
+/* Called from main context */
int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
@@ -432,11 +447,12 @@ int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
}
+/* Called from IO thread context */
void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
pa_sink_input *i;
void *state = NULL;
pa_sink_assert_ref(s);
- pa_assert(PA_SINK_IS_LINKED(s->state));
+ pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
/* Make sure the sink code already reset the counter! */
pa_assert(s->thread_info.rewind_nbytes <= 0);
@@ -451,11 +467,11 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
pa_sink_input_process_rewind(i, nbytes);
}
- if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
+ if (s->monitor_source && PA_SOURCE_IS_OPENED(s->monitor_source->thread_info.state))
pa_source_process_rewind(s->monitor_source, nbytes);
-
}
+/* Called from IO thread context */
static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxinfo) {
pa_sink_input *i;
unsigned n = 0;
@@ -495,24 +511,26 @@ static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, uns
return n;
}
-static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length) {
+/* Called from IO thread context */
+static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
pa_sink_input *i;
void *state = NULL;
unsigned p = 0;
unsigned n_unreffed = 0;
pa_sink_assert_ref(s);
+ pa_assert(result);
+ pa_assert(result->memblock);
+ pa_assert(result->length > 0);
/* We optimize for the case where the order of the inputs has not changed */
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
unsigned j;
- pa_mix_info* m;
+ pa_mix_info* m = NULL;
pa_sink_input_assert_ref(i);
- m = NULL;
-
/* Let's try to find the matching entry info the pa_mix_info array */
for (j = 0; j < n; j ++) {
@@ -527,14 +545,47 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length
}
/* Drop read data */
- pa_sink_input_drop(i, length);
+ pa_sink_input_drop(i, result->length);
+
+ if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) {
+
+ if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
+ void *ostate = NULL;
+ pa_source_output *o;
+ pa_memchunk c;
+
+ if (m && m->chunk.memblock) {
+ c = m->chunk;
+ pa_memblock_ref(c.memblock);
+ pa_assert(result->length <= c.length);
+ c.length = result->length;
+
+ pa_memchunk_make_writable(&c, 0);
+ pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
+ } else {
+ c = s->silence;
+ pa_memblock_ref(c.memblock);
+ pa_assert(result->length <= c.length);
+ c.length = result->length;
+ }
+
+ while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
+ pa_source_output_assert_ref(o);
+ pa_assert(o->direct_on_input == i);
+ pa_source_post_direct(s->monitor_source, o, &c);
+ }
+
+ pa_memblock_unref(c.memblock);
+ }
+ }
if (m) {
- pa_sink_input_unref(m->userdata);
- m->userdata = NULL;
if (m->chunk.memblock)
pa_memblock_unref(m->chunk.memblock);
- pa_memchunk_reset(&m->chunk);
+ pa_memchunk_reset(&m->chunk);
+
+ pa_sink_input_unref(m->userdata);
+ m->userdata = NULL;
n_unreffed += 1;
}
@@ -551,8 +602,12 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length
pa_memblock_unref(info->chunk.memblock);
}
}
+
+ if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
+ pa_source_post(s->monitor_source, result);
}
+/* Called from IO thread context */
void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
pa_mix_info info[MAX_MIX_CHANNELS];
unsigned n;
@@ -621,14 +676,12 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
}
if (s->thread_info.state == PA_SINK_RUNNING)
- inputs_drop(s, info, n, result->length);
-
- if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
- pa_source_post(s->monitor_source, result);
+ inputs_drop(s, info, n, result);
pa_sink_unref(s);
}
+/* Called from IO thread context */
void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
pa_mix_info info[MAX_MIX_CHANNELS];
unsigned n;
@@ -650,6 +703,8 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
if (length > block_size_max)
length = pa_frame_align(block_size_max, &s->sample_spec);
+ pa_assert(length > 0);
+
n = s->thread_info.state == PA_SINK_RUNNING ? fill_mix_info(s, &length, info, MAX_MIX_CHANNELS) : 0;
if (n == 0) {
@@ -673,8 +728,8 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
vchunk = info[0].chunk;
pa_memblock_ref(vchunk.memblock);
- if (vchunk.length > target->length)
- vchunk.length = target->length;
+ if (vchunk.length > length)
+ vchunk.length = length;
if (!pa_cvolume_is_norm(&volume)) {
pa_memchunk_make_writable(&vchunk, 0);
@@ -700,14 +755,12 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
}
if (s->thread_info.state == PA_SINK_RUNNING)
- inputs_drop(s, info, n, target->length);
-
- if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
- pa_source_post(s->monitor_source, target);
+ inputs_drop(s, info, n, target);
pa_sink_unref(s);
}
+/* Called from IO thread context */
void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
pa_memchunk chunk;
size_t l, d;
@@ -739,6 +792,7 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
pa_sink_unref(s);
}
+/* Called from IO thread context */
void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
@@ -757,6 +811,7 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
pa_sink_render_into_full(s, result);
}
+/* Called from main thread */
pa_usec_t pa_sink_get_latency(pa_sink *s) {
pa_usec_t usec = 0;
@@ -768,14 +823,14 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) {
if (!PA_SINK_IS_OPENED(s->state))
return 0;
- if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
- return 0;
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
return usec;
}
+/* Called from main thread */
void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) {
- int changed;
+ pa_bool_t changed;
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
@@ -788,34 +843,36 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) {
s->set_volume = NULL;
if (!s->set_volume)
- pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, NULL, pa_xfree);
+ pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, volume, 0, NULL);
if (changed)
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
+/* Called from main thread */
const pa_cvolume *pa_sink_get_volume(pa_sink *s) {
- struct pa_cvolume old_volume;
-
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
- old_volume = s->volume;
+ if (s->refresh_volume) {
+ struct pa_cvolume old_volume = s->volume;
- if (s->get_volume && s->get_volume(s) < 0)
- s->get_volume = NULL;
+ if (s->get_volume && s->get_volume(s) < 0)
+ s->get_volume = NULL;
- if (!s->get_volume && s->refresh_volume)
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, &s->volume, 0, NULL);
+ if (!s->get_volume)
+ pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, &s->volume, 0, NULL);
- if (!pa_cvolume_equal(&old_volume, &s->volume))
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ if (!pa_cvolume_equal(&old_volume, &s->volume))
+ pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ }
return &s->volume;
}
+/* Called from main thread */
void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
- int changed;
+ pa_bool_t changed;
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
@@ -833,26 +890,29 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
+/* Called from main thread */
pa_bool_t pa_sink_get_mute(pa_sink *s) {
- pa_bool_t old_muted;
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
- old_muted = s->muted;
+ if (s->refresh_muted) {
+ pa_bool_t old_muted = s->muted;
- if (s->get_mute && s->get_mute(s) < 0)
- s->get_mute = NULL;
+ if (s->get_mute && s->get_mute(s) < 0)
+ s->get_mute = NULL;
- if (!s->get_mute && s->refresh_mute)
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &s->muted, 0, NULL);
+ if (!s->get_mute)
+ pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &s->muted, 0, NULL);
- if (old_muted != s->muted)
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ if (old_muted != s->muted)
+ pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ }
return s->muted;
}
+/* Called from main thread */
void pa_sink_set_description(pa_sink *s, const char *description) {
const char *old;
pa_sink_assert_ref(s);
@@ -884,6 +944,7 @@ void pa_sink_set_description(pa_sink *s, const char *description) {
}
}
+/* Called from main thread */
unsigned pa_sink_linked_by(pa_sink *s) {
unsigned ret;
@@ -901,6 +962,7 @@ unsigned pa_sink_linked_by(pa_sink *s) {
return ret;
}
+/* Called from main thread */
unsigned pa_sink_used_by(pa_sink *s) {
unsigned ret;
@@ -916,10 +978,10 @@ unsigned pa_sink_used_by(pa_sink *s) {
return ret - s->n_corked;
}
+/* 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);
pa_sink_assert_ref(s);
- pa_assert(s->thread_info.state != PA_SINK_UNLINKED);
switch ((pa_sink_message_t) code) {
@@ -957,6 +1019,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
pa_sink_input_set_state_within_thread(i, i->state);
pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
+ pa_sink_input_update_max_request(i, s->thread_info.max_request);
pa_sink_invalidate_requested_latency(s);
@@ -975,11 +1038,11 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
* sink input handling a few lines down at
* PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */
- pa_sink_input_set_state_within_thread(i, i->state);
-
if (i->detach)
i->detach(i);
+ pa_sink_input_set_state_within_thread(i, i->state);
+
pa_assert(i->thread_info.attached);
i->thread_info.attached = FALSE;
@@ -1072,6 +1135,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
i->attach(i);
pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
+ pa_sink_input_update_max_request(i, s->thread_info.max_request);
pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
@@ -1122,9 +1186,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
case PA_SINK_MESSAGE_DETACH:
- /* We're detaching all our input streams so that the
- * asyncmsgq and rtpoll fields can be changed without
- * problems */
+ /* Detach all streams */
pa_sink_detach_within_thread(s);
return 0;
@@ -1138,9 +1200,40 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
pa_usec_t *usec = userdata;
*usec = pa_sink_get_requested_latency_within_thread(s);
+
+ if (*usec == (pa_usec_t) -1)
+ *usec = s->thread_info.max_latency;
+
+ return 0;
+ }
+
+ case PA_SINK_MESSAGE_SET_LATENCY_RANGE: {
+ pa_usec_t *r = userdata;
+
+ pa_sink_update_latency_range(s, r[0], r[1]);
+
+ return 0;
+ }
+
+ case PA_SINK_MESSAGE_GET_LATENCY_RANGE: {
+ pa_usec_t *r = userdata;
+
+ r[0] = s->thread_info.min_latency;
+ r[1] = s->thread_info.max_latency;
+
return 0;
}
+ case PA_SINK_MESSAGE_GET_MAX_REWIND:
+
+ *((size_t*) userdata) = s->thread_info.max_rewind;
+ return 0;
+
+ case PA_SINK_MESSAGE_GET_MAX_REQUEST:
+
+ *((size_t*) userdata) = s->thread_info.max_request;
+ return 0;
+
case PA_SINK_MESSAGE_GET_LATENCY:
case PA_SINK_MESSAGE_MAX:
;
@@ -1149,6 +1242,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
return -1;
}
+/* Called from main thread */
int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
pa_sink *sink;
uint32_t idx;
@@ -1162,20 +1256,23 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
return ret;
}
+/* Called from main thread */
void pa_sink_detach(pa_sink *s) {
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
}
+/* Called from main thread */
void pa_sink_attach(pa_sink *s) {
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
}
+/* Called from IO thread */
void pa_sink_detach_within_thread(pa_sink *s) {
pa_sink_input *i;
void *state = NULL;
@@ -1191,6 +1288,7 @@ void pa_sink_detach_within_thread(pa_sink *s) {
pa_source_detach_within_thread(s->monitor_source);
}
+/* Called from IO thread */
void pa_sink_attach_within_thread(pa_sink *s) {
pa_sink_input *i;
void *state = NULL;
@@ -1206,6 +1304,7 @@ void pa_sink_attach_within_thread(pa_sink *s) {
pa_source_attach_within_thread(s->monitor_source);
}
+/* Called from IO thread */
void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
@@ -1224,10 +1323,12 @@ void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
s->request_rewind(s);
}
+/* Called from IO thread */
pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
pa_usec_t result = (pa_usec_t) -1;
pa_sink_input *i;
void *state = NULL;
+ pa_usec_t monitor_latency;
pa_sink_assert_ref(s);
@@ -1240,12 +1341,18 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
(result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
result = i->thread_info.requested_sink_latency;
+ monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
+
+ if (monitor_latency != (pa_usec_t) -1 &&
+ (result == (pa_usec_t) -1 || result > monitor_latency))
+ result = monitor_latency;
+
if (result != (pa_usec_t) -1) {
- if (s->max_latency > 0 && result > s->max_latency)
- result = s->max_latency;
+ if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency)
+ result = s->thread_info.max_latency;
- if (s->min_latency > 0 && result < s->min_latency)
- result = s->min_latency;
+ if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency)
+ result = s->thread_info.min_latency;
}
s->thread_info.requested_latency = result;
@@ -1254,6 +1361,7 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
return result;
}
+/* Called from main thread */
pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
pa_usec_t usec = 0;
@@ -1263,15 +1371,11 @@ pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
if (!PA_SINK_IS_OPENED(s->state))
return 0;
- if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) < 0)
- return 0;
-
- if (usec == (pa_usec_t) -1)
- usec = s->max_latency;
-
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
return usec;
}
+/* Called from IO thread */
void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
pa_sink_input *i;
void *state = NULL;
@@ -1283,20 +1387,145 @@ void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
s->thread_info.max_rewind = max_rewind;
- while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
- pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
+ if (PA_SINK_IS_LINKED(s->thread_info.state)) {
+ while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+ pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
+ }
if (s->monitor_source)
pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
}
+/* Called from IO thread */
+void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
+ pa_sink_input *i;
+ void *state = NULL;
+
+ pa_sink_assert_ref(s);
+
+ if (max_request == s->thread_info.max_request)
+ return;
+
+ s->thread_info.max_request = max_request;
+
+ if (PA_SINK_IS_LINKED(s->thread_info.state)) {
+ while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+ pa_sink_input_update_max_request(i, s->thread_info.max_request);
+ }
+}
+
+/* Called from IO thread */
void pa_sink_invalidate_requested_latency(pa_sink *s) {
+ pa_sink_input *i;
+ void *state = NULL;
pa_sink_assert_ref(s);
- pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
s->thread_info.requested_latency_valid = FALSE;
if (s->update_requested_latency)
s->update_requested_latency(s);
+
+ while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+ if (i->update_sink_requested_latency)
+ i->update_sink_requested_latency(i);
+}
+
+/* Called from main thread */
+void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
+ pa_sink_assert_ref(s);
+
+ /* min_latency == 0: no limit
+ * min_latency == (size_t) -1: default limit
+ * min_latency anything else: specified limit
+ *
+ * Similar for max_latency */
+
+ if (min_latency == (pa_usec_t) -1)
+ min_latency = DEFAULT_MIN_LATENCY;
+
+ if (max_latency == (pa_usec_t) -1)
+ max_latency = min_latency;
+
+ pa_assert(!min_latency || !max_latency ||
+ min_latency <= max_latency);
+
+ if (PA_SINK_IS_LINKED(s->state)) {
+ pa_usec_t r[2];
+
+ r[0] = min_latency;
+ r[1] = max_latency;
+
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
+ } else {
+ s->thread_info.min_latency = min_latency;
+ s->thread_info.max_latency = max_latency;
+
+ s->monitor_source->thread_info.min_latency = min_latency;
+ s->monitor_source->thread_info.max_latency = max_latency;
+
+ s->thread_info.requested_latency_valid = s->monitor_source->thread_info.requested_latency_valid = FALSE;
+ }
+}
+
+/* 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(min_latency);
+ pa_assert(max_latency);
+
+ 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);
+
+ *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 */
+void pa_sink_update_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
+ pa_sink_input *i;
+ void *state = NULL;
+
+ pa_sink_assert_ref(s);
+
+ s->thread_info.min_latency = min_latency;
+ s->thread_info.max_latency = max_latency;
+
+ while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+ if (i->update_sink_latency_range)
+ i->update_sink_latency_range(i);
+
+ pa_sink_invalidate_requested_latency(s);
+
+ pa_source_update_latency_range(s->monitor_source, min_latency, max_latency);
+}
+
+size_t pa_sink_get_max_rewind(pa_sink *s) {
+ size_t r;
+ pa_sink_assert_ref(s);
+
+ if (!PA_SINK_IS_LINKED(s->state))
+ return s->thread_info.max_rewind;
+
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
+
+ return r;
+}
+
+size_t pa_sink_get_max_request(pa_sink *s) {
+ size_t r;
+ pa_sink_assert_ref(s);
+
+ if (!PA_SINK_IS_LINKED(s->state))
+ return s->thread_info.max_request;
+
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0);
+
+ return r;
}
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index f297c8f1..b73944e8 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -1,8 +1,6 @@
#ifndef foopulsesinkhfoo
#define foopulsesinkhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -82,17 +80,15 @@ struct pa_sink {
pa_cvolume volume;
pa_bool_t muted;
- pa_bool_t refresh_volume;
- pa_bool_t refresh_mute;
+
+ pa_bool_t refresh_volume:1;
+ pa_bool_t refresh_muted:1;
pa_asyncmsgq *asyncmsgq;
pa_rtpoll *rtpoll;
pa_memchunk silence;
- pa_usec_t min_latency; /* we won't go below this latency */
- pa_usec_t max_latency; /* An upper limit for the latencies */
-
/* Called when the main loop requests a state change. Called from
* main loop context. If returns -1 the state change will be
* inhibited */
@@ -100,8 +96,9 @@ struct pa_sink {
/* Callled when the volume is queried. Called from main loop
* context. If this is NULL a PA_SINK_MESSAGE_GET_VOLUME message
- * will be sent to the IO thread instead. */
- int (*get_volume)(pa_sink *s); /* may be null */
+ * will be sent to the IO thread instead. If refresh_volume is
+ * FALSE neither this function is called nor a message is sent. */
+ int (*get_volume)(pa_sink *s); /* may be NULL */
/* Called when the volume shall be changed. Called from main loop
* context. If this is NULL a PA_SINK_MESSAGE_SET_VOLUME message
@@ -110,7 +107,8 @@ struct pa_sink {
/* Called when the mute setting is queried. Called from main loop
* context. If this is NULL a PA_SINK_MESSAGE_GET_MUTE message
- * will be sent to the IO thread instead. */
+ * will be sent to the IO thread instead. If refresh_mute is
+ * FALSE neither this function is called nor a message is sent.*/
int (*get_mute)(pa_sink *s); /* dito */
/* Called when the mute setting shall be changed. Called from main
@@ -132,17 +130,24 @@ struct pa_sink {
pa_sink_state_t state;
pa_hashmap *inputs;
pa_cvolume soft_volume;
- pa_bool_t soft_muted;
+ pa_bool_t soft_muted:1;
- pa_bool_t requested_latency_valid;
+ pa_bool_t requested_latency_valid:1;
pa_usec_t requested_latency;
- /* The number of bytes we need keep around to be able to satisfy
- * every DMA buffer rewrite */
+ /* The number of bytes streams need to keep around as history to
+ * be able to satisfy every DMA buffer rewrite */
size_t max_rewind;
+ /* The number of bytes streams need to keep around to satisfy
+ * every DMA write request */
+ size_t max_request;
+
/* Maximum of what clients requested to rewind in this cycle */
size_t rewind_nbytes;
+
+ pa_usec_t min_latency; /* we won't go below this latency */
+ pa_usec_t max_latency; /* An upper limit for the latencies */
} thread_info;
void *userdata;
@@ -165,6 +170,10 @@ typedef enum pa_sink_message {
PA_SINK_MESSAGE_FINISH_MOVE,
PA_SINK_MESSAGE_ATTACH,
PA_SINK_MESSAGE_DETACH,
+ PA_SINK_MESSAGE_SET_LATENCY_RANGE,
+ PA_SINK_MESSAGE_GET_LATENCY_RANGE,
+ PA_SINK_MESSAGE_GET_MAX_REWIND,
+ PA_SINK_MESSAGE_GET_MAX_REQUEST,
PA_SINK_MESSAGE_MAX
} pa_sink_message_t;
@@ -209,6 +218,8 @@ void pa_sink_set_description(pa_sink *s, const char *description);
void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q);
void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p);
+void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency);
+
void pa_sink_detach(pa_sink *s);
void pa_sink_attach(pa_sink *s);
@@ -217,6 +228,10 @@ void pa_sink_attach(pa_sink *s);
/* The returned value is supposed to be in the time domain of the sound card! */
pa_usec_t pa_sink_get_latency(pa_sink *s);
pa_usec_t pa_sink_get_requested_latency(pa_sink *s);
+void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency);
+
+size_t pa_sink_get_max_rewind(pa_sink *s);
+size_t pa_sink_get_max_request(pa_sink *s);
int pa_sink_update_status(pa_sink*s);
int pa_sink_suspend(pa_sink *s, pa_bool_t suspend);
@@ -248,6 +263,9 @@ void pa_sink_detach_within_thread(pa_sink *s);
pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s);
void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind);
+void pa_sink_set_max_request(pa_sink *s, size_t max_request);
+
+void pa_sink_update_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency);
/* To be called exclusively by sink input drivers, from IO context */
diff --git a/src/pulsecore/sioman.c b/src/pulsecore/sioman.c
index 8d4c6fa7..7e5b186c 100644
--- a/src/pulsecore/sioman.c
+++ b/src/pulsecore/sioman.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/sioman.h b/src/pulsecore/sioman.h
index 49fffb34..d0cacc9b 100644
--- a/src/pulsecore/sioman.h
+++ b/src/pulsecore/sioman.h
@@ -1,8 +1,6 @@
#ifndef foosiomanhfoo
#define foosiomanhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c
index a99193b7..e69a63da 100644
--- a/src/pulsecore/socket-client.c
+++ b/src/pulsecore/socket-client.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -61,6 +59,7 @@
#include <pulsecore/core-error.h>
#include <pulsecore/socket-util.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/socket-util.h>
#include <pulsecore/log.h>
#include <pulsecore/parseaddr.h>
#include <pulsecore/macro.h>
@@ -270,22 +269,7 @@ static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size
pa_assert(sa);
pa_assert(salen);
- switch (sa->sa_family) {
- case AF_UNIX:
- c->local = TRUE;
- break;
-
- case AF_INET:
- c->local = ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
- break;
-
- case AF_INET6:
- c->local = memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
- break;
-
- default:
- c->local = FALSE;
- }
+ c->local = pa_socket_address_is_local(sa);
if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) {
pa_log("socket(): %s", pa_cstrerror(errno));
diff --git a/src/pulsecore/socket-client.h b/src/pulsecore/socket-client.h
index 41e8c3bd..9ceeaddc 100644
--- a/src/pulsecore/socket-client.h
+++ b/src/pulsecore/socket-client.h
@@ -1,8 +1,6 @@
#ifndef foosocketclienthfoo
#define foosocketclienthfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c
index 162a1aac..9885a02b 100644
--- a/src/pulsecore/socket-server.c
+++ b/src/pulsecore/socket-server.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -83,7 +81,7 @@ struct pa_socket_server {
char *filename;
char *tcpwrap_service;
- void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata);
+ pa_socket_server_on_connection_cb_t on_connection;
void *userdata;
pa_io_event *io_event;
@@ -91,7 +89,7 @@ struct pa_socket_server {
enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type;
};
-static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) {
+static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
pa_socket_server *s = userdata;
pa_iochannel *io;
int nfd;
@@ -195,9 +193,9 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file
pa_make_fd_cloexec(fd);
+ memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX;
- strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
- sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
+ pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
pa_make_socket_low_delay(fd);
@@ -295,7 +293,7 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad
pa_socket_server *ss;
int fd = -1;
struct sockaddr_in6 sa;
- int on = 1;
+ int on;
pa_assert(m);
pa_assert(port > 0);
@@ -308,11 +306,13 @@ pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t ad
pa_make_fd_cloexec(fd);
#ifdef IPV6_V6ONLY
+ on = 1;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
pa_log("setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno));
#endif
#ifdef SO_REUSEADDR
+ on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
pa_log("setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno));
#endif
@@ -426,7 +426,7 @@ void pa_socket_server_unref(pa_socket_server *s) {
socket_server_free(s);
}
-void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata) {
+void pa_socket_server_set_callback(pa_socket_server*s, pa_socket_server_on_connection_cb_t on_connection, void *userdata) {
pa_assert(s);
pa_assert(PA_REFCNT_VALUE(s) >= 1);
@@ -507,7 +507,6 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
}
pa_snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
-
}
return c;
diff --git a/src/pulsecore/socket-server.h b/src/pulsecore/socket-server.h
index 777599e5..1edfb432 100644
--- a/src/pulsecore/socket-server.h
+++ b/src/pulsecore/socket-server.h
@@ -1,8 +1,6 @@
#ifndef foosocketserverhfoo
#define foosocketserverhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -47,7 +45,9 @@ pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const cha
void pa_socket_server_unref(pa_socket_server*s);
pa_socket_server* pa_socket_server_ref(pa_socket_server *s);
-void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata);
+typedef void (*pa_socket_server_on_connection_cb_t)(pa_socket_server*s, pa_iochannel *io, void *userdata);
+
+void pa_socket_server_set_callback(pa_socket_server*s, pa_socket_server_on_connection_cb_t connection_cb, void *userdata);
char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l);
diff --git a/src/pulsecore/socket-util.c b/src/pulsecore/socket-util.c
index 456accb8..f721f699 100644
--- a/src/pulsecore/socket-util.c
+++ b/src/pulsecore/socket-util.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -129,8 +127,8 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) {
return;
#endif
}
-
}
+
#ifndef OS_IS_WIN32
pa_snprintf(c, l, "Unknown network client");
return;
@@ -284,3 +282,40 @@ int pa_unix_socket_remove_stale(const char *fn) {
}
#endif /* HAVE_SYS_UN_H */
+
+
+pa_bool_t pa_socket_address_is_local(const struct sockaddr *sa) {
+ pa_assert(sa);
+
+ switch (sa->sa_family) {
+ case AF_UNIX:
+ return TRUE;
+
+ case AF_INET:
+ return ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
+
+ case AF_INET6:
+ return memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
+
+ default:
+ return FALSE;
+ }
+}
+
+pa_bool_t pa_socket_is_local(int fd) {
+
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+ struct sockaddr_in6 in6;
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un un;
+#endif
+ } sa;
+ socklen_t sa_len = sizeof(sa);
+
+ if (getpeername(fd, &sa.sa, &sa_len) < 0)
+ return FALSE;
+
+ return pa_socket_address_is_local(&sa.sa);
+}
diff --git a/src/pulsecore/socket-util.h b/src/pulsecore/socket-util.h
index a0344c68..7a40285a 100644
--- a/src/pulsecore/socket-util.h
+++ b/src/pulsecore/socket-util.h
@@ -1,8 +1,6 @@
#ifndef foosocketutilhfoo
#define foosocketutilhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -26,6 +24,9 @@
***/
#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <pulsecore/macro.h>
void pa_socket_peer_to_string(int fd, char *c, size_t l);
@@ -39,4 +40,7 @@ int pa_socket_set_rcvbuf(int fd, size_t l);
int pa_unix_socket_is_stale(const char *fn);
int pa_unix_socket_remove_stale(const char *fn);
+pa_bool_t pa_socket_address_is_local(const struct sockaddr *sa);
+pa_bool_t pa_socket_is_local(int fd);
+
#endif
diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c
index e209676f..8eedf830 100644
--- a/src/pulsecore/sound-file-stream.c
+++ b/src/pulsecore/sound-file-stream.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -35,6 +33,7 @@
#include <sndfile.h>
#include <pulse/xmalloc.h>
+#include <pulse/util.h>
#include <pulsecore/core-error.h>
#include <pulsecore/sink-input.h>
@@ -149,8 +148,6 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk
if (!u->memblockq)
return -1;
- pa_log_debug("pop: %lu", (unsigned long) length);
-
for (;;) {
pa_memchunk tchunk;
size_t fs;
@@ -158,6 +155,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk
sf_count_t n;
if (pa_memblockq_peek(u->memblockq, chunk) >= 0) {
+ chunk->length = PA_MIN(chunk->length, length);
pa_memblockq_drop(u->memblockq, chunk->length);
return 0;
}
@@ -194,11 +192,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk
pa_memblock_unref(tchunk.memblock);
}
- pa_log_debug("peek fail");
-
if (pa_sink_input_safe_to_remove(i)) {
- pa_log_debug("completed to play");
-
pa_memblockq_free(u->memblockq);
u->memblockq = NULL;
@@ -216,6 +210,8 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
u = FILE_STREAM(i->userdata);
file_stream_assert_ref(u);
+ pa_log("backwards %lu", (unsigned long) nbytes);
+
if (!u->memblockq)
return;
@@ -330,7 +326,7 @@ int pa_play_file(
data.driver = __FILE__;
pa_sink_input_new_data_set_sample_spec(&data, &ss);
pa_sink_input_new_data_set_volume(&data, volume);
- pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, fname);
+ pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, pa_path_get_filename(fname));
pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname);
u->sink_input = pa_sink_input_new(sink->core, &data, 0);
diff --git a/src/pulsecore/sound-file-stream.h b/src/pulsecore/sound-file-stream.h
index 189e242d..4cc69146 100644
--- a/src/pulsecore/sound-file-stream.h
+++ b/src/pulsecore/sound-file-stream.h
@@ -1,8 +1,6 @@
#ifndef foosoundfilestreamhfoo
#define foosoundfilestreamhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c
index 3e6f683d..3183ede6 100644
--- a/src/pulsecore/sound-file.c
+++ b/src/pulsecore/sound-file.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -119,10 +117,7 @@ int pa_sound_file_load(
}
if (map)
- if (!pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_DEFAULT)) {
- pa_log("Unsupported channel map in file %s", fname);
- goto finish;
- }
+ pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_DEFAULT);
if ((l = pa_frame_size(ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) {
pa_log("File too large");
diff --git a/src/pulsecore/sound-file.h b/src/pulsecore/sound-file.h
index 46763bd8..e4d703d3 100644
--- a/src/pulsecore/sound-file.h
+++ b/src/pulsecore/sound-file.h
@@ -1,8 +1,6 @@
#ifndef soundfilehfoo
#define soundfilehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 5c36937a..3d1abe30 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -76,12 +74,15 @@ void pa_source_output_new_data_done(pa_source_output_new_data *data) {
pa_proplist_free(data->proplist);
}
+/* Called from main context */
static void reset_callbacks(pa_source_output *o) {
pa_assert(o);
o->push = NULL;
o->process_rewind = NULL;
o->update_max_rewind = NULL;
+ o->update_source_requested_latency = NULL;
+ o->update_source_latency_range = NULL;
o->attach = NULL;
o->detach = NULL;
o->suspend = NULL;
@@ -91,6 +92,7 @@ static void reset_callbacks(pa_source_output *o) {
o->state_change = NULL;
}
+/* Called from main context */
pa_source_output* pa_source_output_new(
pa_core *core,
pa_source_output_new_data *data,
@@ -109,11 +111,13 @@ pa_source_output* pa_source_output_new(
pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
if (!data->source)
- data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, 1);
+ data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, TRUE);
pa_return_null_if_fail(data->source);
pa_return_null_if_fail(pa_source_get_state(data->source) != PA_SOURCE_UNLINKED);
+ pa_return_null_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of);
+
if (!data->sample_spec_is_set)
data->sample_spec = data->source->sample_spec;
@@ -192,6 +196,8 @@ pa_source_output* pa_source_output_new(
o->sample_spec = data->sample_spec;
o->channel_map = data->channel_map;
+ o->direct_on_input = data->direct_on_input;
+
reset_callbacks(o);
o->userdata = NULL;
@@ -200,6 +206,7 @@ pa_source_output* pa_source_output_new(
o->thread_info.sample_spec = o->sample_spec;
o->thread_info.resampler = resampler;
o->thread_info.requested_source_latency = (pa_usec_t) -1;
+ o->thread_info.direct_on_input = o->direct_on_input;
o->thread_info.delay_memblockq = pa_memblockq_new(
0,
@@ -214,6 +221,9 @@ pa_source_output* pa_source_output_new(
pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0);
pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0);
+ if (o->direct_on_input)
+ pa_assert_se(pa_idxset_put(o->direct_on_input->direct_outputs, o, NULL) == 0);
+
pa_log_info("Created output %u \"%s\" on %s with sample spec %s and channel map %s",
o->index,
pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME)),
@@ -226,6 +236,7 @@ pa_source_output* pa_source_output_new(
return o;
}
+/* Called from main context */
static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) {
pa_assert(o);
@@ -237,14 +248,14 @@ static void update_n_corked(pa_source_output *o, pa_source_output_state_t state)
pa_source_update_status(o->source);
}
+/* Called from main context */
static int source_output_set_state(pa_source_output *o, pa_source_output_state_t state) {
pa_assert(o);
if (o->state == state)
return 0;
- if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0)
- return -1;
+ pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
update_n_corked(o, state);
o->state = state;
@@ -255,6 +266,7 @@ static int source_output_set_state(pa_source_output *o, pa_source_output_state_t
return 0;
}
+/* Called from main context */
void pa_source_output_unlink(pa_source_output*o) {
pa_bool_t linked;
pa_assert(o);
@@ -269,6 +281,8 @@ void pa_source_output_unlink(pa_source_output*o) {
if (linked)
pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o);
+ if (o->direct_on_input)
+ pa_idxset_remove_by_data(o->direct_on_input->direct_outputs, o, NULL);
pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL);
if (pa_idxset_remove_by_data(o->source->outputs, o, NULL))
pa_source_output_unref(o);
@@ -278,7 +292,7 @@ void pa_source_output_unlink(pa_source_output*o) {
if (linked)
if (o->source->asyncmsgq)
- pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0);
reset_callbacks(o);
@@ -291,6 +305,7 @@ void pa_source_output_unlink(pa_source_output*o) {
pa_source_output_unref(o);
}
+/* Called from main context */
static void source_output_free(pa_object* mo) {
pa_source_output *o = PA_SOURCE_OUTPUT(mo);
@@ -317,45 +332,52 @@ static void source_output_free(pa_object* mo) {
pa_xfree(o);
}
+/* Called from main context */
void pa_source_output_put(pa_source_output *o) {
pa_source_output_state_t state;
pa_source_output_assert_ref(o);
pa_assert(o->state == PA_SOURCE_OUTPUT_INIT);
+
+ /* The following fields must be initialized properly */
pa_assert(o->push);
+ pa_assert(o->kill);
state = o->flags & PA_SOURCE_OUTPUT_START_CORKED ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING;
update_n_corked(o, state);
o->state = state;
- pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0);
pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index);
pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], o);
}
+/* Called from main context */
void pa_source_output_kill(pa_source_output*o) {
pa_source_output_assert_ref(o);
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
- if (o->kill)
- o->kill(o);
+ o->kill(o);
}
-pa_usec_t pa_source_output_get_latency(pa_source_output *o) {
- pa_usec_t r = 0;
+/* Called from main context */
+pa_usec_t pa_source_output_get_latency(pa_source_output *o, pa_usec_t *source_latency) {
+ pa_usec_t r[2] = { 0, 0 };
pa_source_output_assert_ref(o);
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
- if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, &r, 0, NULL) < 0)
- r = 0;
+ pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0);
if (o->get_latency)
- r += o->get_latency(o);
+ r[0] += o->get_latency(o);
- return r;
+ if (source_latency)
+ *source_latency = r[1];
+
+ return r[0];
}
/* Called from thread context */
@@ -368,10 +390,10 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
pa_assert(chunk);
pa_assert(pa_frame_aligned(chunk->length, &o->source->sample_spec));
- if (!o->push || o->state == PA_SOURCE_OUTPUT_CORKED)
+ if (!o->push || o->thread_info.state == PA_SOURCE_OUTPUT_CORKED)
return;
- pa_assert(o->state == PA_SOURCE_OUTPUT_RUNNING);
+ pa_assert(o->thread_info.state == PA_SOURCE_OUTPUT_RUNNING);
if (pa_memblockq_push(o->thread_info.delay_memblockq, chunk) < 0) {
pa_log_debug("Delay queue overflow!");
@@ -409,7 +431,8 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
if (rchunk.length > 0)
o->push(o, &rchunk);
- pa_memblock_unref(rchunk.memblock);
+ if (rchunk.memblock)
+ pa_memblock_unref(rchunk.memblock);
}
pa_memblock_unref(qchunk.memblock);
@@ -421,7 +444,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in sink sample spec */) {
pa_source_output_assert_ref(o);
- pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
+ pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec));
if (nbytes <= 0)
@@ -455,42 +478,44 @@ void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* i
o->update_max_rewind(o, o->thread_info.resampler ? pa_resampler_result(o->thread_info.resampler, nbytes) : nbytes);
}
+/* Called from thread context */
static pa_usec_t fixup_latency(pa_source *s, pa_usec_t usec) {
pa_source_assert_ref(s);
if (usec == (pa_usec_t) -1)
return usec;
- if (s->max_latency > 0 && usec > s->max_latency)
- usec = s->max_latency;
+ if (s->thread_info.max_latency > 0 && usec > s->thread_info.max_latency)
+ usec = s->thread_info.max_latency;
- if (s->min_latency > 0 && usec < s->min_latency)
- usec = s->min_latency;
+ if (s->thread_info.min_latency > 0 && usec < s->thread_info.min_latency)
+ usec = s->thread_info.min_latency;
return usec;
}
+/* Called from thread context */
pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec) {
pa_source_output_assert_ref(o);
usec = fixup_latency(o->source, usec);
-
o->thread_info.requested_source_latency = usec;
pa_source_invalidate_requested_latency(o->source);
return usec;
}
+/* Called from main context */
pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) {
pa_source_output_assert_ref(o);
- usec = fixup_latency(o->source, usec);
-
if (PA_SOURCE_OUTPUT_IS_LINKED(o->state))
- pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL);
+ pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
else {
/* If this sink input is not realized yet, we have to touch
* the thread info data directly */
+
+ usec = fixup_latency(o->source, usec);
o->thread_info.requested_source_latency = usec;
o->source->thread_info.requested_latency_valid = FALSE;
}
@@ -498,13 +523,14 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t
return usec;
}
+/* Called from main context */
pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) {
pa_usec_t usec = 0;
pa_source_output_assert_ref(o);
if (PA_SOURCE_OUTPUT_IS_LINKED(o->state))
- pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
else
/* If this sink input is not realized yet, we have to touch
* the thread info data directly */
@@ -513,6 +539,7 @@ pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) {
return usec;
}
+/* Called from main context */
void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
pa_source_output_assert_ref(o);
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
@@ -520,6 +547,7 @@ void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING);
}
+/* Called from main context */
int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
pa_source_output_assert_ref(o);
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
@@ -536,6 +564,7 @@ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
return 0;
}
+/* Called from main context */
void pa_source_output_set_name(pa_source_output *o, const char *name) {
const char *old;
pa_source_output_assert_ref(o);
@@ -559,12 +588,14 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) {
}
}
+/* Called from main context */
pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
pa_source_output_assert_ref(o);
return o->resample_method;
}
+/* Called from main context */
int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
pa_source *origin;
pa_resampler *new_resampler;
@@ -582,6 +613,9 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE)
return -1;
+ if (o->direct_on_input)
+ return -1;
+
if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
pa_log_warn("Failed to move source output: too many outputs per source.");
return -1;
@@ -619,7 +653,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], &hook_data);
/* Okey, let's move it */
- pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0);
pa_idxset_remove_by_data(origin->outputs, o, NULL);
pa_idxset_put(dest->outputs, o, NULL);
@@ -652,7 +686,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
pa_source_update_status(origin);
pa_source_update_status(dest);
- pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0);
if (o->moved)
o->moved(o);
@@ -667,6 +701,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
return 0;
}
+/* Called from IO thread context */
void pa_source_output_set_state_within_thread(pa_source_output *o, pa_source_output_state_t state) {
pa_source_output_assert_ref(o);
@@ -679,19 +714,22 @@ void pa_source_output_set_state_within_thread(pa_source_output *o, pa_source_out
o->thread_info.state = state;
}
-/* Called from thread context */
+/* Called from IO thread context, except when it is not */
int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int64_t offset, pa_memchunk* chunk) {
pa_source_output *o = PA_SOURCE_OUTPUT(mo);
-
pa_source_output_assert_ref(o);
- pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
switch (code) {
case PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY: {
pa_usec_t *r = userdata;
+ pa_usec_t source_usec = 0;
+
+ r[0] += pa_bytes_to_usec(pa_memblockq_get_length(o->thread_info.delay_memblockq), &o->source->sample_spec);
+
+ if (o->source->parent.process_msg(PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_GET_LATENCY, &source_usec, 0, NULL) >= 0)
+ r[1] += source_usec;
- *r += pa_bytes_to_usec(pa_memblockq_get_length(o->thread_info.delay_memblockq), &o->source->sample_spec);
return 0;
}
@@ -706,10 +744,13 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int
pa_source_output_set_state_within_thread(o, PA_PTR_TO_UINT(userdata));
return 0;
- case PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY:
+ case PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY: {
+ pa_usec_t *usec = userdata;
+
+ *usec = pa_source_output_set_requested_latency_within_thread(o, *usec);
- pa_source_output_set_requested_latency_within_thread(o, (pa_usec_t) offset);
return 0;
+ }
case PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY: {
pa_usec_t *r = userdata;
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index 2dadb5c4..61825b22 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -1,8 +1,6 @@
#ifndef foopulsesourceoutputhfoo
#define foopulsesourceoutputhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -66,13 +64,17 @@ struct pa_source_output {
pa_source_output_state_t state;
pa_source_output_flags_t flags;
- pa_proplist *proplist;
char *driver; /* may be NULL */
+ pa_proplist *proplist;
+
pa_module *module; /* may be NULL */
pa_client *client; /* may be NULL */
pa_source *source;
+ /* 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 */
+
pa_sample_spec sample_spec;
pa_channel_map channel_map;
@@ -80,16 +82,24 @@ struct pa_source_output {
/* Pushes a new memchunk into the output. Called from IO thread
* context. */
- void (*push)(pa_source_output *o, const pa_memchunk *chunk);
+ void (*push)(pa_source_output *o, const pa_memchunk *chunk); /* may NOT be NULL */
/* Only relevant for monitor sources right now: called when the
- * recorded stream is rewound. Called from IO context*/
- void (*process_rewind)(pa_source_output *o, size_t nbytes);
+ * recorded stream is rewound. Called from IO context */
+ void (*process_rewind)(pa_source_output *o, size_t nbytes); /* may be NULL */
/* Called whenever the maximum rewindable size of the source
* changes. Called from IO thread context. */
void (*update_max_rewind) (pa_source_output *o, size_t nbytes); /* may be NULL */
+ /* Called whenever the configured latency of the source
+ * changes. Called from IO context. */
+ void (*update_source_requested_latency) (pa_source_output *o); /* may be NULL */
+
+ /* Called whenver the latency range of the source changes. Called
+ * from IO context. */
+ void (*update_source_latency_range) (pa_source_output *o); /* may be NULL */
+
/* If non-NULL this function is called when the output is first
* connected to a source. Called from IO thread context */
void (*attach) (pa_source_output *o); /* may be NULL */
@@ -108,12 +118,12 @@ struct pa_source_output {
/* Supposed to unlink and destroy this stream. Called from main
* context. */
- void (*kill)(pa_source_output* o); /* may be NULL */
+ void (*kill)(pa_source_output* o); /* may NOT be NULL */
/* Return the current latency (i.e. length of bufferd audio) of
- this stream. Called from main context. If NULL a
- PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY message is sent to the IO
- thread instead. */
+ this stream. Called from main context. This is added to what the
+ PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY message sent to the IO thread
+ returns */
pa_usec_t (*get_latency) (pa_source_output *o); /* may be NULL */
/* If non_NULL this function is called from thread context if the
@@ -135,6 +145,8 @@ struct pa_source_output {
/* The requested latency for the source */
pa_usec_t requested_source_latency;
+
+ pa_sink_input *direct_on_input; /* may be NULL */
} thread_info;
void *userdata;
@@ -154,6 +166,7 @@ enum {
typedef struct pa_source_output_new_data {
pa_proplist *proplist;
+ pa_sink_input *direct_on_input;
const char *driver;
pa_module *module;
@@ -202,7 +215,7 @@ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate);
/* External code may request disconnection with this funcion */
void pa_source_output_kill(pa_source_output*o);
-pa_usec_t pa_source_output_get_latency(pa_source_output *i);
+pa_usec_t pa_source_output_get_latency(pa_source_output *i, pa_usec_t *source_latency);
pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o);
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index c767abcf..8256a988 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -99,6 +97,7 @@ void pa_source_new_data_done(pa_source_new_data *data) {
pa_proplist_free(data->proplist);
}
+/* Called from main context */
static void reset_callbacks(pa_source *s) {
pa_assert(s);
@@ -110,6 +109,7 @@ static void reset_callbacks(pa_source *s) {
s->update_requested_latency = NULL;
}
+/* Called from main context */
pa_source* pa_source_new(
pa_core *core,
pa_source_new_data *data,
@@ -120,6 +120,8 @@ pa_source* pa_source_new(
char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
pa_assert(core);
+ pa_assert(data);
+ pa_assert(data->name);
s = pa_msgobject_new(pa_source);
@@ -128,6 +130,8 @@ pa_source* pa_source_new(
return NULL;
}
+ pa_source_new_data_set_name(data, name);
+
if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) {
pa_xfree(s);
pa_namereg_unregister(core, name);
@@ -195,16 +199,15 @@ pa_source* pa_source_new(
&s->sample_spec,
0);
- s->min_latency = DEFAULT_MIN_LATENCY;
- s->max_latency = s->min_latency;
-
s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
- s->thread_info.soft_volume = s->volume;
- s->thread_info.soft_muted = s->muted;
+ pa_cvolume_reset(&s->thread_info.soft_volume, s->sample_spec.channels);
+ s->thread_info.soft_muted = FALSE;
s->thread_info.state = s->state;
s->thread_info.max_rewind = 0;
s->thread_info.requested_latency_valid = FALSE;
s->thread_info.requested_latency = 0;
+ s->thread_info.min_latency = DEFAULT_MIN_LATENCY;
+ s->thread_info.max_latency = 0;
pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0);
@@ -217,6 +220,7 @@ pa_source* pa_source_new(
return s;
}
+/* Called from main context */
static int source_set_state(pa_source *s, pa_source_state_t state) {
int ret;
pa_bool_t suspend_change;
@@ -235,8 +239,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state) {
return -1;
if (s->asyncmsgq)
- if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0)
- return -1;
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
s->state = state;
@@ -257,24 +260,32 @@ static int source_set_state(pa_source *s, pa_source_state_t state) {
return 0;
}
+/* Called from main context */
void pa_source_put(pa_source *s) {
pa_source_assert_ref(s);
pa_assert(s->state == PA_SINK_INIT);
+
+ /* The following fields must be initialized properly when calling _put() */
pa_assert(s->asyncmsgq);
pa_assert(s->rtpoll);
+ pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency ||
+ s->thread_info.min_latency <= s->thread_info.max_latency);
- pa_assert(!s->min_latency || !s->max_latency || s->min_latency <= s->max_latency);
-
- if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL))
+ if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL)) {
s->flags |= PA_SOURCE_DECIBEL_VOLUME;
+ s->thread_info.soft_volume = s->volume;
+ s->thread_info.soft_muted = s->muted;
+ }
+
pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
}
+/* Called from main context */
void pa_source_unlink(pa_source *s) {
pa_bool_t linked;
pa_source_output *o, *j = NULL;
@@ -312,6 +323,7 @@ void pa_source_unlink(pa_source *s) {
}
}
+/* Called from main context */
static void source_free(pa_object *o) {
pa_source_output *so;
pa_source *s = PA_SOURCE(o);
@@ -343,18 +355,21 @@ static void source_free(pa_object *o) {
pa_xfree(s);
}
+/* Called from main context */
void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
pa_source_assert_ref(s);
s->asyncmsgq = q;
}
+/* Called from main context */
void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
pa_source_assert_ref(s);
s->rtpoll = p;
}
+/* Called from main context */
int pa_source_update_status(pa_source*s) {
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
@@ -365,6 +380,7 @@ int pa_source_update_status(pa_source*s) {
return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
}
+/* Called from main context */
int pa_source_suspend(pa_source *s, pa_bool_t suspend) {
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
@@ -375,6 +391,7 @@ int pa_source_suspend(pa_source *s, pa_bool_t suspend) {
return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
}
+/* Called from IO thread context */
void pa_source_process_rewind(pa_source *s, size_t nbytes) {
pa_source_output *o;
void *state = NULL;
@@ -393,6 +410,7 @@ void pa_source_process_rewind(pa_source *s, size_t nbytes) {
}
}
+/* Called from IO thread context */
void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
pa_source_output *o;
void *state = NULL;
@@ -417,7 +435,9 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
pa_source_output_assert_ref(o);
- pa_source_output_push(o, &vchunk);
+
+ if (!o->thread_info.direct_on_input)
+ pa_source_output_push(o, &vchunk);
}
pa_memblock_unref(vchunk.memblock);
@@ -425,11 +445,43 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
pa_source_output_assert_ref(o);
- pa_source_output_push(o, chunk);
+
+ if (!o->thread_info.direct_on_input)
+ pa_source_output_push(o, chunk);
}
}
}
+/* Called from IO thread context */
+void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
+ pa_source_assert_ref(s);
+ pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state));
+ pa_source_output_assert_ref(o);
+ pa_assert(o->thread_info.direct_on_input);
+ pa_assert(chunk);
+
+ if (s->thread_info.state != PA_SOURCE_RUNNING)
+ return;
+
+ if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
+ pa_memchunk vchunk = *chunk;
+
+ pa_memblock_ref(vchunk.memblock);
+ pa_memchunk_make_writable(&vchunk, 0);
+
+ if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
+ pa_silence_memchunk(&vchunk, &s->sample_spec);
+ else
+ pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
+
+ pa_source_output_push(o, &vchunk);
+
+ pa_memblock_unref(vchunk.memblock);
+ } else
+ pa_source_output_push(o, chunk);
+}
+
+/* Called from main thread */
pa_usec_t pa_source_get_latency(pa_source *s) {
pa_usec_t usec;
@@ -439,14 +491,14 @@ pa_usec_t pa_source_get_latency(pa_source *s) {
if (!PA_SOURCE_IS_OPENED(s->state))
return 0;
- if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
- return 0;
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
return usec;
}
+/* Called from main thread */
void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
- int changed;
+ pa_bool_t changed;
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
@@ -459,34 +511,36 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
s->set_volume = NULL;
if (!s->set_volume)
- pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, NULL, pa_xfree);
+ pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, volume, 0, NULL);
if (changed)
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
+/* Called from main thread */
const pa_cvolume *pa_source_get_volume(pa_source *s) {
- pa_cvolume old_volume;
-
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
- old_volume = s->volume;
+ if (s->refresh_volume) {
+ pa_cvolume old_volume = s->volume;
- if (s->get_volume && s->get_volume(s) < 0)
- s->get_volume = NULL;
+ if (s->get_volume && s->get_volume(s) < 0)
+ s->get_volume = NULL;
- if (!s->get_volume && s->refresh_volume)
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, &s->volume, 0, NULL);
+ if (!s->get_volume)
+ pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, &s->volume, 0, NULL);
- if (!pa_cvolume_equal(&old_volume, &s->volume))
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ if (!pa_cvolume_equal(&old_volume, &s->volume))
+ pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ }
return &s->volume;
}
+/* Called from main thread */
void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
- int changed;
+ pa_bool_t changed;
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
@@ -504,26 +558,29 @@ void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
+/* Called from main thread */
pa_bool_t pa_source_get_mute(pa_source *s) {
- pa_bool_t old_muted;
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
- old_muted = s->muted;
+ if (s->refresh_muted) {
+ pa_bool_t old_muted = s->muted;
- if (s->get_mute && s->get_mute(s) < 0)
- s->get_mute = NULL;
+ if (s->get_mute && s->get_mute(s) < 0)
+ s->get_mute = NULL;
- if (!s->get_mute && s->refresh_muted)
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, &s->muted, 0, NULL);
+ if (!s->get_mute)
+ pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, &s->muted, 0, NULL);
- if (old_muted != s->muted)
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ if (old_muted != s->muted)
+ pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ }
return s->muted;
}
+/* Called from main thread */
void pa_source_set_description(pa_source *s, const char *description) {
const char *old;
pa_source_assert_ref(s);
@@ -547,6 +604,7 @@ void pa_source_set_description(pa_source *s, const char *description) {
}
}
+/* Called from main thread */
unsigned pa_source_linked_by(pa_source *s) {
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
@@ -554,6 +612,7 @@ unsigned pa_source_linked_by(pa_source *s) {
return pa_idxset_size(s->outputs);
}
+/* Called from main thread */
unsigned pa_source_used_by(pa_source *s) {
unsigned ret;
@@ -566,17 +625,23 @@ unsigned pa_source_used_by(pa_source *s) {
return ret - s->n_corked;
}
+/* Called from IO thread, except when it is not */
int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
pa_source *s = PA_SOURCE(object);
pa_source_assert_ref(s);
- pa_assert(s->thread_info.state != PA_SOURCE_UNLINKED);
switch ((pa_source_message_t) code) {
+
case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
+ if (o->direct_on_input) {
+ o->thread_info.direct_on_input = o->direct_on_input;
+ pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
+ }
+
pa_assert(!o->thread_info.attached);
o->thread_info.attached = TRUE;
@@ -606,6 +671,11 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_
pa_assert(o->thread_info.attached);
o->thread_info.attached = FALSE;
+ if (o->thread_info.direct_on_input) {
+ pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
+ o->thread_info.direct_on_input = NULL;
+ }
+
if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
pa_source_output_unref(o);
@@ -636,9 +706,7 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_
case PA_SOURCE_MESSAGE_DETACH:
- /* We're detaching all our output streams so that the
- * asyncmsgq and rtpoll fields can be changed without
- * problems */
+ /* Detach all streams */
pa_source_detach_within_thread(s);
return 0;
@@ -652,10 +720,45 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_
pa_usec_t *usec = userdata;
*usec = pa_source_get_requested_latency_within_thread(s);
+
+ if (*usec == (pa_usec_t) -1)
+ *usec = s->thread_info.max_latency;
+
+ return 0;
+ }
+
+ case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
+ pa_usec_t *r = userdata;
+
+ pa_source_update_latency_range(s, r[0], r[1]);
+
+ return 0;
+ }
+
+ case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
+ pa_usec_t *r = userdata;
+
+ r[0] = s->thread_info.min_latency;
+ r[1] = s->thread_info.max_latency;
+
return 0;
}
+ case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
+
+ *((size_t*) userdata) = s->thread_info.max_rewind;
+ return 0;
+
case PA_SOURCE_MESSAGE_GET_LATENCY:
+
+ if (s->monitor_of) {
+ *((pa_usec_t*) userdata) = 0;
+ return 0;
+ }
+
+ /* Implementors need to overwrite this implementation! */
+ return -1;
+
case PA_SOURCE_MESSAGE_MAX:
;
}
@@ -663,6 +766,7 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_
return -1;
}
+/* Called from main thread */
int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
uint32_t idx;
pa_source *source;
@@ -676,20 +780,23 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
return ret;
}
+/* Called from main thread */
void pa_source_detach(pa_source *s) {
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
}
+/* Called from main thread */
void pa_source_attach(pa_source *s) {
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
- pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL);
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
}
+/* Called from IO thread */
void pa_source_detach_within_thread(pa_source *s) {
pa_source_output *o;
void *state = NULL;
@@ -702,6 +809,7 @@ void pa_source_detach_within_thread(pa_source *s) {
o->detach(o);
}
+/* Called from IO thread */
void pa_source_attach_within_thread(pa_source *s) {
pa_source_output *o;
void *state = NULL;
@@ -714,6 +822,7 @@ void pa_source_attach_within_thread(pa_source *s) {
o->attach(o);
}
+/* Called from IO thread */
pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
pa_usec_t result = (pa_usec_t) -1;
pa_source_output *o;
@@ -731,11 +840,11 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
result = o->thread_info.requested_source_latency;
if (result != (pa_usec_t) -1) {
- if (s->max_latency > 0 && result > s->max_latency)
- result = s->max_latency;
+ if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency)
+ result = s->thread_info.max_latency;
- if (s->min_latency > 0 && result < s->min_latency)
- result = s->min_latency;
+ if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency)
+ result = s->thread_info.min_latency;
}
s->thread_info.requested_latency = result;
@@ -744,6 +853,7 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
return result;
}
+/* Called from main thread */
pa_usec_t pa_source_get_requested_latency(pa_source *s) {
pa_usec_t usec;
@@ -753,15 +863,12 @@ pa_usec_t pa_source_get_requested_latency(pa_source *s) {
if (!PA_SOURCE_IS_OPENED(s->state))
return 0;
- if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) < 0)
- return 0;
-
- if (usec == (pa_usec_t) -1)
- usec = s->max_latency;
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
return usec;
}
+/* Called from IO thread */
void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
pa_source_output *o;
void *state = NULL;
@@ -773,17 +880,106 @@ void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
s->thread_info.max_rewind = max_rewind;
- while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
- pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
+ if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
+ while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
+ pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
+ }
}
void pa_source_invalidate_requested_latency(pa_source *s) {
+ pa_source_output *o;
+ void *state = NULL;
pa_source_assert_ref(s);
- pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
s->thread_info.requested_latency_valid = FALSE;
if (s->update_requested_latency)
s->update_requested_latency(s);
+
+ while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
+ o->update_source_requested_latency(o);
+
+ if (s->monitor_of)
+ pa_sink_invalidate_requested_latency(s->monitor_of);
+}
+
+void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
+ pa_source_assert_ref(s);
+
+ /* min_latency == 0: no limit
+ * min_latency == (size_t) -1: default limit
+ * min_latency anything else: specified limit
+ *
+ * Similar for max_latency */
+
+ if (min_latency == (pa_usec_t) -1)
+ min_latency = DEFAULT_MIN_LATENCY;
+
+ if (max_latency == (pa_usec_t) -1)
+ max_latency = min_latency;
+
+ pa_assert(!min_latency || !max_latency ||
+ min_latency <= max_latency);
+
+ if (PA_SINK_IS_LINKED(s->state)) {
+ pa_usec_t r[2];
+
+ r[0] = min_latency;
+ r[1] = max_latency;
+
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
+ } else {
+ s->thread_info.min_latency = min_latency;
+ s->thread_info.max_latency = max_latency;
+
+ s->thread_info.requested_latency_valid = FALSE;
+ }
+}
+
+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(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 */
+void pa_source_update_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
+ pa_source_output *o;
+ void *state = NULL;
+
+ pa_source_assert_ref(s);
+
+ s->thread_info.min_latency = min_latency;
+ s->thread_info.max_latency = max_latency;
+
+ while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
+ if (o->update_source_latency_range)
+ o->update_source_latency_range(o);
+
+ pa_source_invalidate_requested_latency(s);
+}
+
+size_t pa_source_get_max_rewind(pa_source *s) {
+ size_t r;
+ pa_source_assert_ref(s);
+
+ if (!PA_SOURCE_IS_LINKED(s->state))
+ return s->thread_info.max_rewind;
+
+ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
+
+ return r;
}
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index f9c9cbf9..f4a17e8d 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -1,8 +1,6 @@
#ifndef foopulsesourcehfoo
#define foopulsesourcehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -42,6 +40,7 @@ typedef struct pa_source pa_source;
#include <pulsecore/asyncmsgq.h>
#include <pulsecore/msgobject.h>
#include <pulsecore/rtpoll.h>
+#include <pulsecore/source-output.h>
#define PA_MAX_OUTPUTS_PER_SOURCE 32
@@ -84,22 +83,44 @@ struct pa_source {
pa_cvolume volume;
pa_bool_t muted;
- pa_bool_t refresh_volume;
- pa_bool_t refresh_muted;
+
+ pa_bool_t refresh_volume:1;
+ pa_bool_t refresh_muted:1;
pa_asyncmsgq *asyncmsgq;
pa_rtpoll *rtpoll;
pa_memchunk silence;
- pa_usec_t min_latency; /* we won't go below this latency setting */
- pa_usec_t max_latency; /* An upper limit for the latencies */
-
+ /* Called when the main loop requests a state change. Called from
+ * main loop context. If returns -1 the state change will be
+ * inhibited */
int (*set_state)(pa_source*source, pa_source_state_t state); /* may be NULL */
- int (*set_volume)(pa_source *s); /* dito */
+
+ /* Callled when the volume is queried. Called from main loop
+ * context. If this is NULL a PA_SOURCE_MESSAGE_GET_VOLUME message
+ * will be sent to the IO thread instead. If refresh_volume is
+ * FALSE neither this function is called nor a message is sent. */
int (*get_volume)(pa_source *s); /* dito */
- int (*set_mute)(pa_source *s); /* dito */
+
+ /* Called when the volume shall be changed. Called from main loop
+ * context. If this is NULL a PA_SOURCE_MESSAGE_SET_VOLUME message
+ * will be sent to the IO thread instead. */
+ int (*set_volume)(pa_source *s); /* dito */
+
+ /* Called when the mute setting is queried. Called from main loop
+ * context. If this is NULL a PA_SOURCE_MESSAGE_GET_MUTE message
+ * will be sent to the IO thread instead. If refresh_mute is
+ * FALSE neither this function is called nor a message is sent.*/
int (*get_mute)(pa_source *s); /* dito */
+
+ /* Called when the mute setting shall be changed. Called from main
+ * loop context. If this is NULL a PA_SOURCE_MESSAGE_SET_MUTE
+ * message will be sent to the IO thread instead. */
+ int (*set_mute)(pa_source *s); /* dito */
+
+ /* Called when a the requested latency is changed. Called from IO
+ * thread context. */
void (*update_requested_latency)(pa_source *s); /* dito */
/* Contains copies of the above data so that the real-time worker
@@ -108,14 +129,17 @@ struct pa_source {
pa_source_state_t state;
pa_hashmap *outputs;
pa_cvolume soft_volume;
- pa_bool_t soft_muted;
+ pa_bool_t soft_muted:1;
- pa_bool_t requested_latency_valid;
- size_t requested_latency;
+ pa_bool_t requested_latency_valid:1;
+ pa_usec_t requested_latency;
/* Then number of bytes this source will be rewound for at
- * max */
+ * max. (Only used on monitor sources) */
size_t max_rewind;
+
+ pa_usec_t min_latency; /* we won't go below this latency */
+ pa_usec_t max_latency; /* An upper limit for the latencies */
} thread_info;
void *userdata;
@@ -136,6 +160,9 @@ typedef enum pa_source_message {
PA_SOURCE_MESSAGE_SET_STATE,
PA_SOURCE_MESSAGE_ATTACH,
PA_SOURCE_MESSAGE_DETACH,
+ PA_SOURCE_MESSAGE_SET_LATENCY_RANGE,
+ PA_SOURCE_MESSAGE_GET_LATENCY_RANGE,
+ PA_SOURCE_MESSAGE_GET_MAX_REWIND,
PA_SOURCE_MESSAGE_MAX
} pa_source_message_t;
@@ -180,13 +207,19 @@ void pa_source_set_description(pa_source *s, const char *description);
void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q);
void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p);
+void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency);
+
void pa_source_detach(pa_source *s);
void pa_source_attach(pa_source *s);
/* May be called by everyone, from main context */
+/* The returned value is supposed to be in the time domain of the sound card! */
pa_usec_t pa_source_get_latency(pa_source *s);
pa_usec_t pa_source_get_requested_latency(pa_source *s);
+void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency);
+
+size_t pa_source_get_max_rewind(pa_source *s);
int pa_source_update_status(pa_source*s);
int pa_source_suspend(pa_source *s, pa_bool_t suspend);
@@ -203,7 +236,8 @@ unsigned pa_source_used_by(pa_source *s); /* Number of connected streams that ar
/* To be called exclusively by the source driver, from IO context */
-void pa_source_post(pa_source*s, const pa_memchunk *b);
+void pa_source_post(pa_source*s, const pa_memchunk *chunk);
+void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk);
void pa_source_process_rewind(pa_source *s, size_t nbytes);
int pa_source_process_msg(pa_msgobject *o, int code, void *userdata, int64_t, pa_memchunk *chunk);
@@ -214,6 +248,7 @@ void pa_source_detach_within_thread(pa_source *s);
pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s);
void pa_source_set_max_rewind(pa_source *s, size_t max_rewind);
+void pa_source_update_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency);
/* To be called exclusively by source output drivers, from IO context */
diff --git a/src/pulsecore/speexwrap.h b/src/pulsecore/speexwrap.h
index df73edf0..617e4afb 100644
--- a/src/pulsecore/speexwrap.h
+++ b/src/pulsecore/speexwrap.h
@@ -1,8 +1,6 @@
#ifndef foopulsespeexwraphfoo
#define foopulsespeexwraphfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/start-child.c b/src/pulsecore/start-child.c
index e01011d6..1661383d 100644
--- a/src/pulsecore/start-child.c
+++ b/src/pulsecore/start-child.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/start-child.h b/src/pulsecore/start-child.h
index 359b5044..0b5ff660 100644
--- a/src/pulsecore/start-child.h
+++ b/src/pulsecore/start-child.h
@@ -1,8 +1,6 @@
#ifndef foopulsestartchildhfoo
#define foopulsestartchildhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/strbuf.c b/src/pulsecore/strbuf.c
index 7c576c67..b59b6f49 100644
--- a/src/pulsecore/strbuf.c
+++ b/src/pulsecore/strbuf.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/strbuf.h b/src/pulsecore/strbuf.h
index d3555a2c..24c876d5 100644
--- a/src/pulsecore/strbuf.h
+++ b/src/pulsecore/strbuf.h
@@ -1,8 +1,6 @@
#ifndef foostrbufhfoo
#define foostrbufhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/strlist.c b/src/pulsecore/strlist.c
index ac83f6b1..f587a2f8 100644
--- a/src/pulsecore/strlist.c
+++ b/src/pulsecore/strlist.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/strlist.h b/src/pulsecore/strlist.h
index 6e6e2d4a..1cb7537a 100644
--- a/src/pulsecore/strlist.h
+++ b/src/pulsecore/strlist.h
@@ -1,8 +1,6 @@
#ifndef foostrlisthfoo
#define foostrlisthfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c
index 7616cd16..b0ed59ef 100644
--- a/src/pulsecore/tagstruct.c
+++ b/src/pulsecore/tagstruct.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h
index 8699e6c8..e7d07054 100644
--- a/src/pulsecore/tagstruct.h
+++ b/src/pulsecore/tagstruct.h
@@ -1,8 +1,6 @@
#ifndef footagstructhfoo
#define footagstructhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/thread-mq.c b/src/pulsecore/thread-mq.c
index 7e39c577..34f92a7e 100644
--- a/src/pulsecore/thread-mq.c
+++ b/src/pulsecore/thread-mq.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/thread-mq.h b/src/pulsecore/thread-mq.h
index 0ae49f8c..3b5e0e78 100644
--- a/src/pulsecore/thread-mq.h
+++ b/src/pulsecore/thread-mq.h
@@ -1,8 +1,6 @@
#ifndef foopulsethreadmqhfoo
#define foopulsethreadmqhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c
index 7f43f43e..20ed16d9 100644
--- a/src/pulsecore/thread-posix.c
+++ b/src/pulsecore/thread-posix.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/thread-win32.c b/src/pulsecore/thread-win32.c
index cad1420a..c40d3342 100644
--- a/src/pulsecore/thread-win32.c
+++ b/src/pulsecore/thread-win32.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h
index 54ef320e..f3aca13e 100644
--- a/src/pulsecore/thread.h
+++ b/src/pulsecore/thread.h
@@ -1,8 +1,6 @@
#ifndef foopulsethreadhfoo
#define foopulsethreadhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c
index 9b4be29f..fe5a4f18 100644
--- a/src/pulsecore/time-smoother.c
+++ b/src/pulsecore/time-smoother.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -451,3 +449,11 @@ pa_usec_t pa_smoother_translate(pa_smoother *s, pa_usec_t x, pa_usec_t y_delay)
return (pa_usec_t) ((double) y_delay / nde);
}
+
+void pa_smoother_reset(pa_smoother *s) {
+ pa_assert(s);
+
+ s->n_history = 0;
+ s->abc_valid = FALSE;
+
+}
diff --git a/src/pulsecore/time-smoother.h b/src/pulsecore/time-smoother.h
index b301b48c..2051e640 100644
--- a/src/pulsecore/time-smoother.h
+++ b/src/pulsecore/time-smoother.h
@@ -1,8 +1,6 @@
#ifndef foopulsetimesmootherhfoo
#define foopulsetimesmootherhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -46,4 +44,6 @@ void pa_smoother_set_time_offset(pa_smoother *s, pa_usec_t x_offset);
void pa_smoother_pause(pa_smoother *s, pa_usec_t x);
void pa_smoother_resume(pa_smoother *s, pa_usec_t x);
+void pa_smoother_reset(pa_smoother *s);
+
#endif
diff --git a/src/pulsecore/tokenizer.c b/src/pulsecore/tokenizer.c
index cf5da648..d1e0836b 100644
--- a/src/pulsecore/tokenizer.c
+++ b/src/pulsecore/tokenizer.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/tokenizer.h b/src/pulsecore/tokenizer.h
index 68a8db49..d51cd73e 100644
--- a/src/pulsecore/tokenizer.h
+++ b/src/pulsecore/tokenizer.h
@@ -1,8 +1,6 @@
#ifndef footokenizerhfoo
#define footokenizerhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/x11prop.c b/src/pulsecore/x11prop.c
index a740e39b..9e75f63a 100644
--- a/src/pulsecore/x11prop.c
+++ b/src/pulsecore/x11prop.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/x11prop.h b/src/pulsecore/x11prop.h
index 388c5a34..c5998d3e 100644
--- a/src/pulsecore/x11prop.h
+++ b/src/pulsecore/x11prop.h
@@ -1,8 +1,6 @@
#ifndef foox11prophfoo
#define foox11prophfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/pulsecore/x11wrap.c b/src/pulsecore/x11wrap.c
index 800a9458..00b6a157 100644
--- a/src/pulsecore/x11wrap.c
+++ b/src/pulsecore/x11wrap.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -63,7 +61,8 @@ struct pa_x11_wrapper {
struct pa_x11_client {
PA_LLIST_FIELDS(pa_x11_client);
pa_x11_wrapper *wrapper;
- int (*callback)(pa_x11_wrapper *w, XEvent *e, void *userdata);
+ pa_x11_event_cb_t event_cb;
+ pa_x11_kill_cb_t kill_cb;
void *userdata;
};
@@ -72,17 +71,23 @@ static void work(pa_x11_wrapper *w) {
pa_assert(w);
pa_assert(PA_REFCNT_VALUE(w) >= 1);
+ pa_x11_wrapper_ref(w);
+
while (XPending(w->display)) {
- pa_x11_client *c;
+ pa_x11_client *c, *n;
XEvent e;
XNextEvent(w->display, &e);
- for (c = w->clients; c; c = c->next) {
- pa_assert(c->callback);
- if (c->callback(w, &e, c->userdata) != 0)
- break;
+ for (c = w->clients; c; c = n) {
+ n = c->next;
+
+ if (c->event_cb)
+ if (c->event_cb(w, &e, c->userdata) != 0)
+ break;
}
}
+
+ pa_x11_wrapper_unref(w);
}
/* IO notification event for the X11 display connection */
@@ -251,7 +256,24 @@ Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) {
return w->display;
}
-pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) {
+void pa_x11_wrapper_kill(pa_x11_wrapper *w) {
+ pa_x11_client *c, *n;
+
+ pa_assert(w);
+
+ pa_x11_wrapper_ref(w);
+
+ for (c = w->clients; c; c = n) {
+ n = c->next;
+
+ if (c->kill_cb)
+ c->kill_cb(w, c->userdata);
+ }
+
+ pa_x11_wrapper_unref(w);
+}
+
+pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, pa_x11_event_cb_t event_cb, pa_x11_kill_cb_t kill_cb, void *userdata) {
pa_x11_client *c;
pa_assert(w);
@@ -259,7 +281,8 @@ pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w,
c = pa_xnew(pa_x11_client, 1);
c->wrapper = w;
- c->callback = cb;
+ c->event_cb = event_cb;
+ c->kill_cb = kill_cb;
c->userdata = userdata;
PA_LLIST_PREPEND(pa_x11_client, w->clients, c);
diff --git a/src/pulsecore/x11wrap.h b/src/pulsecore/x11wrap.h
index 9bed2fce..badc3a1f 100644
--- a/src/pulsecore/x11wrap.h
+++ b/src/pulsecore/x11wrap.h
@@ -1,8 +1,6 @@
#ifndef foox11wraphfoo
#define foox11wraphfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -30,6 +28,11 @@
typedef struct pa_x11_wrapper pa_x11_wrapper;
+typedef struct pa_x11_client pa_x11_client;
+
+typedef int (*pa_x11_event_cb_t)(pa_x11_wrapper *w, XEvent *e, void *userdata);
+typedef void (*pa_x11_kill_cb_t)(pa_x11_wrapper *w, void *userdata);
+
/* Return the X11 wrapper for this core. In case no wrapper was
existant before, allocate a new one */
pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name);
@@ -43,10 +46,11 @@ void pa_x11_wrapper_unref(pa_x11_wrapper* w);
/* Return the X11 display object for this connection */
Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w);
-typedef struct pa_x11_client pa_x11_client;
+/* Kill the connection to the X11 display */
+void pa_x11_wrapper_kill(pa_x11_wrapper *w);
/* Register an X11 client, that is called for each X11 event */
-pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata);
+pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, pa_x11_event_cb_t event_cb, pa_x11_kill_cb_t kill_cb, void *userdata);
/* Free an X11 client object */
void pa_x11_client_free(pa_x11_client *c);
diff --git a/src/tests/asyncmsgq-test.c b/src/tests/asyncmsgq-test.c
index 380c5e7f..08ad3dd4 100644
--- a/src/tests/asyncmsgq-test.c
+++ b/src/tests/asyncmsgq-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/asyncq-test.c b/src/tests/asyncq-test.c
index 0e10ed89..4e8a1207 100644
--- a/src/tests/asyncq-test.c
+++ b/src/tests/asyncq-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/channelmap-test.c b/src/tests/channelmap-test.c
index d26d2cff..9c234602 100644
--- a/src/tests/channelmap-test.c
+++ b/src/tests/channelmap-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
#include <stdio.h>
#include <assert.h>
@@ -22,12 +20,15 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) {
fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map));
+ pa_channel_map_init_extend(&map, 14, PA_CHANNEL_MAP_ALSA);
+
+ fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map));
+
pa_channel_map_parse(&map2, cm);
assert(pa_channel_map_equal(&map, &map2));
pa_channel_map_parse(&map2, "left,test");
-
return 0;
}
diff --git a/src/tests/close-test.c b/src/tests/close-test.c
new file mode 100644
index 00000000..7a6fec57
--- /dev/null
+++ b/src/tests/close-test.c
@@ -0,0 +1,20 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <pulsecore/core-util.h>
+
+int main(int argc, char *argv[]) {
+
+ open("/dev/null", O_RDONLY);
+ open("/dev/null", O_RDONLY);
+ open("/dev/null", O_RDONLY);
+ open("/dev/null", O_RDONLY);
+
+ pa_close_all(5, -1);
+
+ return 0;
+}
diff --git a/src/tests/cpulimit-test.c b/src/tests/cpulimit-test.c
index 4563c0f6..b7145e8a 100644
--- a/src/tests/cpulimit-test.c
+++ b/src/tests/cpulimit-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/envelope-test.c b/src/tests/envelope-test.c
index 240747d7..9f914553 100644
--- a/src/tests/envelope-test.c
+++ b/src/tests/envelope-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/flist-test.c b/src/tests/flist-test.c
index 7e54454e..b2c648da 100644
--- a/src/tests/flist-test.c
+++ b/src/tests/flist-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/get-binary-name-test.c b/src/tests/get-binary-name-test.c
index 29ebbe22..7c7a8996 100644
--- a/src/tests/get-binary-name-test.c
+++ b/src/tests/get-binary-name-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/hook-list-test.c b/src/tests/hook-list-test.c
index 8628f521..60b965cd 100644
--- a/src/tests/hook-list-test.c
+++ b/src/tests/hook-list-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -7,12 +5,12 @@
#include <pulsecore/hook-list.h>
#include <pulsecore/log.h>
-static pa_hook_result_t func1(const char*hook_data, const char*call_data, const char*slot_data) {
+static pa_hook_result_t func1(const char *hook_data, const char *call_data, const char *slot_data) {
pa_log("(func1) hook=%s call=%s slot=%s", hook_data, call_data, slot_data);
return PA_HOOK_OK;
}
-static pa_hook_result_t func2(const char*hook_data, const char*call_data, const char*slot_data) {
+static pa_hook_result_t func2(const char *hook_data, const char *call_data, const char *slot_data) {
pa_log("(func2) hook=%s call=%s slot=%s", hook_data, call_data, slot_data);
return PA_HOOK_OK;
}
@@ -23,9 +21,9 @@ int main(int argc, char *argv[]) {
pa_hook_init(&hook, (void*) "hook");
- pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "slot1");
- slot = pa_hook_connect(&hook, (pa_hook_cb_t) func2, (void*) "slot2");
- pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "slot3");
+ pa_hook_connect(&hook, PA_HOOK_LATE, (pa_hook_cb_t) func1, (void*) "slot1");
+ slot = pa_hook_connect(&hook, PA_HOOK_NORMAL, (pa_hook_cb_t) func2, (void*) "slot2");
+ pa_hook_connect(&hook, PA_HOOK_NORMAL, (pa_hook_cb_t) func1, (void*) "slot3");
pa_hook_fire(&hook, (void*) "call1");
diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c
index f894d2f3..9d930774 100644
--- a/src/tests/interpol-test.c
+++ b/src/tests/interpol-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/ipacl-test.c b/src/tests/ipacl-test.c
index d1bcb3e3..bcdd469a 100644
--- a/src/tests/ipacl-test.c
+++ b/src/tests/ipacl-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
diff --git a/src/tests/mainloop-test.c b/src/tests/mainloop-test.c
index 79a4aaa0..9fa2e466 100644
--- a/src/tests/mainloop-test.c
+++ b/src/tests/mainloop-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c
index 79dd5797..9e358359 100644
--- a/src/tests/mcalign-test.c
+++ b/src/tests/mcalign-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/memblock-test.c b/src/tests/memblock-test.c
index 2b9d3401..6da1b1e9 100644
--- a/src/tests/memblock-test.c
+++ b/src/tests/memblock-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c
index 3fa8d79f..7bf992a1 100644
--- a/src/tests/memblockq-test.c
+++ b/src/tests/memblockq-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/mix-test.c b/src/tests/mix-test.c
index d07b1b0c..f3f6f829 100644
--- a/src/tests/mix-test.c
+++ b/src/tests/mix-test.c
@@ -1,5 +1,3 @@
-/* $Id: resampler-test.c 2037 2007-11-09 02:45:07Z lennart $ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/pacat-simple.c b/src/tests/pacat-simple.c
index c2123b74..b26e4b68 100644
--- a/src/tests/pacat-simple.c
+++ b/src/tests/pacat-simple.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/parec-simple.c b/src/tests/parec-simple.c
index 9c66cc23..6c0d529b 100644
--- a/src/tests/parec-simple.c
+++ b/src/tests/parec-simple.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/proplist-test.c b/src/tests/proplist-test.c
index 5f7a78f3..20041af6 100644
--- a/src/tests/proplist-test.c
+++ b/src/tests/proplist-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/queue-test.c b/src/tests/queue-test.c
index b357ab10..105f094a 100644
--- a/src/tests/queue-test.c
+++ b/src/tests/queue-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/remix-test.c b/src/tests/remix-test.c
index d2fa6943..4777c150 100644
--- a/src/tests/remix-test.c
+++ b/src/tests/remix-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/resampler-test.c b/src/tests/resampler-test.c
index 820a0c1e..1a20be2c 100644
--- a/src/tests/resampler-test.c
+++ b/src/tests/resampler-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/rtpoll-test.c b/src/tests/rtpoll-test.c
index af942104..953fd61d 100644
--- a/src/tests/rtpoll-test.c
+++ b/src/tests/rtpoll-test.c
@@ -1,5 +1,3 @@
-/* $Id: thread-test.c 1621 2007-08-10 22:00:22Z lennart $ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/rtstutter.c b/src/tests/rtstutter.c
index 39dfc5d3..91e85c36 100644
--- a/src/tests/rtstutter.c
+++ b/src/tests/rtstutter.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -75,7 +73,7 @@ static void* work(void *p) {
end.tv_sec += nsec / PA_NSEC_PER_SEC;
end.tv_nsec += nsec % PA_NSEC_PER_SEC;
- while (end.tv_nsec > PA_NSEC_PER_SEC) {
+ while ((pa_usec_t) end.tv_nsec > PA_NSEC_PER_SEC) {
end.tv_sec++;
end.tv_nsec -= PA_NSEC_PER_SEC;
}
diff --git a/src/tests/sig2str-test.c b/src/tests/sig2str-test.c
index 52cb9db4..d64a8902 100644
--- a/src/tests/sig2str-test.c
+++ b/src/tests/sig2str-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/smoother-test.c b/src/tests/smoother-test.c
index de037724..b78f3c91 100644
--- a/src/tests/smoother-test.c
+++ b/src/tests/smoother-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/stripnul.c b/src/tests/stripnul.c
index 2f87e877..0ab06776 100644
--- a/src/tests/stripnul.c
+++ b/src/tests/stripnul.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/sync-playback.c b/src/tests/sync-playback.c
index 63510eb6..7ab3a25c 100644
--- a/src/tests/sync-playback.c
+++ b/src/tests/sync-playback.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c
index ac6d5049..7a62f85a 100644
--- a/src/tests/thread-mainloop-test.c
+++ b/src/tests/thread-mainloop-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/thread-test.c b/src/tests/thread-test.c
index 72dde6cb..f29b5e71 100644
--- a/src/tests/thread-test.c
+++ b/src/tests/thread-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/tests/utf8-test.c b/src/tests/utf8-test.c
index b9594dcc..f1708ad4 100644
--- a/src/tests/utf8-test.c
+++ b/src/tests/utf8-test.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
#include <stdio.h>
#include <assert.h>
diff --git a/src/tests/voltest.c b/src/tests/voltest.c
index 91752ad9..d2c0ff69 100644
--- a/src/tests/voltest.c
+++ b/src/tests/voltest.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
#include <stdio.h>
#include <pulse/volume.h>
diff --git a/src/utils/pabrowse.c b/src/utils/pabrowse.c
index d88001ef..f2ed9553 100644
--- a/src/utils/pabrowse.c
+++ b/src/utils/pabrowse.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/utils/pacat.c b/src/utils/pacat.c
index fc9d56d6..ee784a99 100644
--- a/src/utils/pacat.c
+++ b/src/utils/pacat.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c
index dff9af9d..67d95252 100644
--- a/src/utils/pacmd.c
+++ b/src/utils/pacmd.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -65,7 +63,9 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char*argv[]) {
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX;
- cli = pa_runtime_path("cli");
+ if (!(cli = pa_runtime_path("cli")))
+ goto fail;
+
pa_strlcpy(sa.sun_path, cli, sizeof(sa.sun_path));
pa_xfree(cli);
diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index 1f875a88..4cca2f86 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/utils/padsp b/src/utils/padsp
index c70c3af7..4fe175c2 100755
--- a/src/utils/padsp
+++ b/src/utils/padsp
@@ -1,7 +1,5 @@
#!/bin/sh
-# $Id$
-#
# This file is part of PulseAudio.
#
# Copyright 2006 Lennart Poettering
diff --git a/src/utils/padsp.c b/src/utils/padsp.c
index e43a0de2..d650707e 100644
--- a/src/utils/padsp.c
+++ b/src/utils/padsp.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/utils/paplay.c b/src/utils/paplay.c
index fddbb18c..1b6228b1 100644
--- a/src/utils/paplay.c
+++ b/src/utils/paplay.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/utils/pasuspender.c b/src/utils/pasuspender.c
index 05d96a68..5b4885db 100644
--- a/src/utils/pasuspender.c
+++ b/src/utils/pasuspender.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/utils/pax11publish.c b/src/utils/pax11publish.c
index 9a50f8ef..eee7b6a8 100644
--- a/src/utils/pax11publish.c
+++ b/src/utils/pax11publish.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/todo b/todo
index f579bebe..da993a21 100644
--- a/todo
+++ b/todo
@@ -1,5 +1,3 @@
-*** $Id$ ***
-
Build System:
- Remove symdef files and use macros (like most other projects)
- Use own name mangling scheme instead of ltdl's, which will eliminate the
@@ -11,11 +9,10 @@ Porting:
I18N:
- iconv stuff sent from utils to server (UTF-8)
- iconv sample loading in server
-- Document utf8.h, timeval.h and util.h
- gettextify pulseaudio
Cleanups:
-- drop dependency of libpolyp on libX11, instead use an external mini binary
+- drop dependency of libpulse on libX11, instead use an external mini binary
- module-tunnel: improve latency calculation
- use software volume when hardware doesn't support all channels (alsa done)
- using POSIX monotonous clocks wherever possible instead of gettimeofday()
@@ -30,22 +27,17 @@ Auth/Crypto:
- sasl auth
Features:
-- alsa driver with hw mixing
-- "window manager for sound"
- chroot()
- use scatter/gather io for sockets
- CODECs to reduce bandwidth usage (plug-in based)
- multiline configuration statements
- paplay needs to set a channel map. our default is only correct for AIFF.
(we need help from libsndfile for this)
-- Fix a way for the threading API to handle state and subscription callbacks
- in a nice way.
- examine if it is possible to mimic esd's handling of half duplex cards
(switch to capture when a recording client connects and drop playback during
that time)
- Support for device selection in waveout driver
- add an API to libpulse for allocating memory from the pa_context memory pool
-- allow buffer metric changes during runtime
- better ".include" command in configuration files. should have glob support.
- recursive .if
@@ -55,5 +47,3 @@ Long term:
Backends for:
- portaudio (semi-done)
-- sdl
-- xine (needs update)