# HG changeset patch # User Andrew John Hughes # Date 1456938231 0 # Node ID e5d122ba61c0a21392312dd7820f2596e5539d2c # Parent 8f185d6f0164fa13986f30e950f1c77cdb3279dc PR1741: Break PulseAudio provider out into IcedTea-Sound 2014-06-11 Andrew John Hughes PR1741: Break PulseAudio provider out into IcedTea-Sound * patches/pulse-soundproperties.patch, * pulseaudio/COPYING, * pulseaudio/README, * pulseaudio/src/java/META-INF/services/javax.sound.sampled.spi.MixerProvider, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextEvent.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextListener.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Debug.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/EventLoop.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Operation.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioLine.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerInfo.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerProvider.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPlaybackLine.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPort.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourcePort.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetPort.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioVolumeControl.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/SecurityWrapper.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Stream.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamBufferAttributes.java, * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamSampleSpecification.java, * pulseaudio/src/native/jni-common.c, * pulseaudio/src/native/jni-common.h, * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_ContextEvent.c, * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_EventLoop.c, * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_Operation.c, * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_PulseAudioSourcePort.c, * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_PulseAudioTargetPort.c, * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_Stream.c, * pulseaudio/testsounds/README, * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/OtherSoundProvidersAvailableTest.java, * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java, * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioEventLoopOverhead.java, * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerProviderTest.java, * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerRawTest.java, * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerTest.java, * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLineRawTest.java, * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLineTest.java, * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourcePortTest.java, * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLineTest.java, * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetPortTest.java: Moved to IcedTea-Sound. * INSTALL: Remove PulseAudio references. * Makefile.am: (PULSE_JAVA_DIR): Removed. (PULSE_JAVA_NATIVE_SRCDIR): Likewise. (PULSE_JAVA_NATIVE_SRCS): Likewise. (PULSE_JAVA_BUILDDIR): Likewise. (PULSE_JAVA_NATIVE_BUILDDIR): Likewise. (PULSE_JAVA_NATIVE_OBJECTS): Likewise. (PULSE_JAVA_JAVA_SRCDIR): Likewise. (PULSE_JAVA_CLASS_DIR): Likewise. (PULSE_JAVA_TARGET): Removed. (ICEDTEA_PATCHES): Drop PulseAudio patch. (PULSEAUDIO_SRCS): Removed. (EXTRA_DIST): Removed PULSEAUDIO_SRCS. (clean-local): Remove clean-pulse-java. (icedtea-configure): Remove PULSE_JAVA_TARGET. (icedtea): Remove PulseAudio provider installation. (icedtea-debug-configure): Remove PULSE_JAVA_TARGET. (icedtea-debug): Remove PulseAudio provider installation. (pulse-java): Removed. (pulse-java-class): Likewise. (pulse-java-jar): Likewise. (pulse-java-headers): Likewise. ($(PULSE_JAVA_NATIVE_BUILDDIR)/%.o): Likewise. ($(PULSE_JAVA_NATIVE_BUILDDIR)/libpulse-java.so): Likewise. (clean-pulse-java): Likewise. * NEWS: Updated. * configure.ac: Remove --enable-pulse-java option and PulseAudio library checks. diff -r 8f185d6f0164 -r e5d122ba61c0 ChangeLog --- a/ChangeLog Mon Oct 03 16:35:35 2011 +0200 +++ b/ChangeLog Wed Mar 02 17:03:51 2016 +0000 @@ -1,3 +1,84 @@ +2014-06-11 Andrew John Hughes + + PR1741: Break PulseAudio provider out into IcedTea-Sound + * patches/pulse-soundproperties.patch, + * pulseaudio/COPYING, + * pulseaudio/README, + * pulseaudio/src/java/META-INF/services/javax.sound.sampled.spi.MixerProvider, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextEvent.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextListener.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Debug.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/EventLoop.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Operation.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioLine.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerInfo.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerProvider.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPlaybackLine.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPort.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourcePort.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetPort.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioVolumeControl.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/SecurityWrapper.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Stream.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamBufferAttributes.java, + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamSampleSpecification.java, + * pulseaudio/src/native/jni-common.c, + * pulseaudio/src/native/jni-common.h, + * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_ContextEvent.c, + * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_EventLoop.c, + * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_Operation.c, + * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_PulseAudioSourcePort.c, + * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_PulseAudioTargetPort.c, + * pulseaudio/src/native/org_classpath_icedtea_pulseaudio_Stream.c, + * pulseaudio/testsounds/README, + * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/OtherSoundProvidersAvailableTest.java, + * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java, + * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioEventLoopOverhead.java, + * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerProviderTest.java, + * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerRawTest.java, + * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerTest.java, + * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLineRawTest.java, + * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLineTest.java, + * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourcePortTest.java, + * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLineTest.java, + * pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetPortTest.java: + Moved to IcedTea-Sound. + * INSTALL: Remove PulseAudio references. + * Makefile.am: + (PULSE_JAVA_DIR): Removed. + (PULSE_JAVA_NATIVE_SRCDIR): Likewise. + (PULSE_JAVA_NATIVE_SRCS): Likewise. + (PULSE_JAVA_BUILDDIR): Likewise. + (PULSE_JAVA_NATIVE_BUILDDIR): Likewise. + (PULSE_JAVA_NATIVE_OBJECTS): Likewise. + (PULSE_JAVA_JAVA_SRCDIR): Likewise. + (PULSE_JAVA_CLASS_DIR): Likewise. + (PULSE_JAVA_TARGET): Removed. + (ICEDTEA_PATCHES): Drop PulseAudio patch. + (PULSEAUDIO_SRCS): Removed. + (EXTRA_DIST): Removed PULSEAUDIO_SRCS. + (clean-local): Remove clean-pulse-java. + (icedtea-configure): Remove PULSE_JAVA_TARGET. + (icedtea): Remove PulseAudio provider installation. + (icedtea-debug-configure): Remove PULSE_JAVA_TARGET. + (icedtea-debug): Remove PulseAudio provider installation. + (pulse-java): Removed. + (pulse-java-class): Likewise. + (pulse-java-jar): Likewise. + (pulse-java-headers): Likewise. + ($(PULSE_JAVA_NATIVE_BUILDDIR)/%.o): Likewise. + ($(PULSE_JAVA_NATIVE_BUILDDIR)/libpulse-java.so): Likewise. + (clean-pulse-java): Likewise. + * NEWS: Updated. + * configure.ac: + Remove --enable-pulse-java option and PulseAudio library + checks. + 2011-10-03 Xerxes RĂ„nby Robert Lougher diff -r 8f185d6f0164 -r e5d122ba61c0 INSTALL --- a/INSTALL Mon Oct 03 16:35:35 2011 +0200 +++ b/INSTALL Wed Mar 02 17:03:51 2016 +0000 @@ -27,7 +27,6 @@ libjpeg-devel >= 6b zlib-devel libffi (for --enable-zero or on archs other than x86/x86_64/sparc) -pulseaudio-libs-devel >= 0.9.11 (for --enable-pulse-java) LLVM 2.5 or later (for --enable-shark) systemtap-sdl-devel >= 0.9.5 (Java method tracing requires systemtap >= 0.9.9) @@ -148,7 +147,6 @@ * --disable-hotspot-tests: Disable the running of the HotSpot JTReg suite. * --disable-langtools-tests: Disable the running of the langtools JTReg suite. * --disable-jdk-tests: Disable the running of the jdk JTreg suite. -* --enable-pulse-java: Build the PulseAudio sound provider. * --disable-xrender: Don't include the XRender pipeline. * --enable-systemtap: Include support for tracing using systemtap. * --enable-nss: Enable the NSS security provider. @@ -175,13 +173,6 @@ as a way of avoiding running the extensive JDK test suite which takes several hours. -The PulseAudio provider -======================= - -IcedTea7 includes an implementation of the javax.sound.* APIs using -PulseAudio which can be enabled using --enable-pulse-java. The resulting -provider is org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider. - Xrender Support =============== diff -r 8f185d6f0164 -r e5d122ba61c0 Makefile.am --- a/Makefile.am Mon Oct 03 16:35:35 2011 +0200 +++ b/Makefile.am Wed Mar 02 17:03:51 2016 +0000 @@ -79,16 +79,6 @@ CORBA = openjdk-boot/corba/src/share/classes JAXWS = openjdk-boot/jaxws/src/share/jaxws_classes -PULSE_JAVA_DIR = $(abs_top_srcdir)/pulseaudio -PULSE_JAVA_NATIVE_SRCDIR = $(PULSE_JAVA_DIR)/src/native -PULSE_JAVA_NATIVE_SRCS = $(wildcard $(PULSE_JAVA_NATIVE_SRCDIR)/*.c) -PULSE_JAVA_BUILDDIR = $(abs_top_builddir)/pulseaudio.build -PULSE_JAVA_NATIVE_BUILDDIR = $(PULSE_JAVA_BUILDDIR)/native -PULSE_JAVA_NATIVE_OBJECTS = \ - $(subst $(PULSE_JAVA_NATIVE_SRCDIR),$(PULSE_JAVA_NATIVE_BUILDDIR),$(patsubst %.c,%.o,$(PULSE_JAVA_NATIVE_SRCS))) -PULSE_JAVA_JAVA_SRCDIR = $(PULSE_JAVA_DIR)/src/java -PULSE_JAVA_CLASS_DIR = $(PULSE_JAVA_BUILDDIR)/classes - OPENJDK_SOURCEPATH_DIRS = \ $(SHARE):$(SOLARIS):$(LANGTOOLS):$(CORBA):$(JAXWS) @@ -145,10 +135,6 @@ REV_ARG = -r $(HGREV) endif -if ENABLE_PULSE_JAVA -PULSE_JAVA_TARGET = stamps/pulse-java.stamp -endif - # This should not depend on bootstrapping # but on whether MEMORY_LIMIT is accepted # as an argument to javac @@ -255,11 +241,6 @@ patches/cacao/ignore-tests.patch endif -if ENABLE_PULSE_JAVA -ICEDTEA_PATCHES += \ - patches/pulse-soundproperties.patch -endif - if BUILD_JAMVM ICEDTEA_PATCHES += \ patches/jamvm/find_class_from_caller.patch @@ -585,27 +566,14 @@ $(top_srcdir)/test/jtreg/JavaTest.cmdMgrs.lst \ $(top_srcdir)/test/jtreg/excludelist.langtools.jtx -PULSEAUDIO_SRCS = $(top_srcdir)/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/*.java \ - $(top_srcdir)/pulseaudio/src/java/META-INF/services/javax.sound.sampled.spi.MixerProvider \ - $(top_srcdir)/pulseaudio/src/native/*.h \ - $(top_srcdir)/pulseaudio/src/native/*.c \ - $(top_srcdir)/pulseaudio/TODO \ - $(top_srcdir)/pulseaudio/README \ - $(top_srcdir)/pulseaudio/testsounds/README \ - $(top_srcdir)/pulseaudio/testsounds/startup.wav \ - $(top_srcdir)/pulseaudio/testsounds/logout.wav \ - $(top_srcdir)/pulseaudio/testsounds/error.wav \ - $(top_srcdir)/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/*.java \ - $(top_srcdir)/pulseaudio/COPYING - DESKTOP_FILES = jconsole.desktop policytool.desktop EXTRA_DIST = $(top_srcdir)/patches/*.patch \ $(top_srcdir)/patches/cacao/*.patch \ $(top_srcdir)/patches/jamvm/*.patch \ tools-copy contrib overlays \ - $(JTREG_SRCS) $(DESKTOP_FILES) HACKING \ - $(PULSEAUDIO_SRCS) autogen.sh \ + $(JTREG_SRCS) $(DESKTOP_FILES) \ + HACKING autogen.sh \ tapset/hotspot.stp.in \ tapset/hotspot_jni.stp.in \ tapset/jstack.stp.in \ @@ -630,7 +598,7 @@ fi \ fi -clean-local: clean-tests clean-pulse-java \ +clean-local: clean-tests \ clean-icedtea clean-icedtea-debug clean-icedtea-boot clean-clone clean-clone-boot \ clean-bootstrap-directory-stage1 clean-bootstrap-directory-stage2 \ clean-bootstrap-directory-symlink-stage1 clean-bootstrap-directory-symlink-stage2 \ @@ -1576,7 +1544,7 @@ # you change it in the icedtea-debug target as well. stamps/icedtea-configure.stamp: stamps/bootstrap-directory-symlink-stage2.stamp \ stamps/download.stamp stamps/extract.stamp $(OPENJDK_TREE) \ - stamps/cacao.stamp $(PULSE_JAVA_TARGET) stamps/jamvm.stamp + stamps/cacao.stamp stamps/jamvm.stamp mkdir -p $(BUILD_OUTPUT_DIR) cd $(BUILD_OUTPUT_DIR) && \ $(SHELL) $(abs_top_builddir)/openjdk/configure $(ICEDTEA_CONFIGURE) @@ -1593,16 +1561,6 @@ mkdir -p $(BUILD_JRE_DIR)/lib/$(INSTALL_ARCH_DIR) mkdir -p $(BUILD_SDK_DIR)/jre/lib/ext mkdir -p $(BUILD_JRE_DIR)/lib/ext -if ENABLE_PULSE_JAVA - cp -pPRf $(PULSE_JAVA_NATIVE_BUILDDIR)/libpulse-java.so \ - $(BUILD_SDK_DIR)/jre/lib/$(INSTALL_ARCH_DIR) - cp -pPRf $(PULSE_JAVA_NATIVE_BUILDDIR)/libpulse-java.so \ - $(BUILD_JRE_DIR)/lib/$(INSTALL_ARCH_DIR) - cp -pPRf pulse-java.jar $(BUILD_SDK_DIR)/jre/lib/ext - cp -pPRf pulse-java.jar $(BUILD_JRE_DIR)/lib/ext - (cd $(PULSE_JAVA_JAVA_SRCDIR) && \ - $(ZIP) -qur $(BUILD_SDK_DIR)/src.zip org ) -endif if ZERO_BUILD printf -- '-zero ALIASED_TO -server\n' >> $(BUILD_JRE_ARCH_DIR)/jvm.cfg endif @@ -1647,7 +1605,7 @@ stamps/icedtea-debug-configure.stamp: stamps/bootstrap-directory-symlink-stage2.stamp \ stamps/download.stamp stamps/extract.stamp $(OPENJDK_TREE) \ - stamps/cacao.stamp $(PULSE_JAVA_TARGET) stamps/jamvm.stamp + stamps/cacao.stamp stamps/jamvm.stamp mkdir -p $(DEBUG_BUILD_OUTPUT_DIR) cd $(DEBUG_BUILD_OUTPUT_DIR) && \ $(SHELL) $(abs_top_builddir)/openjdk/configure $(ICEDTEA_CONFIGURE) \ @@ -1665,18 +1623,6 @@ mkdir -p $(BUILD_DEBUG_JRE_DIR)/lib/$(INSTALL_ARCH_DIR) mkdir -p $(BUILD_DEBUG_SDK_DIR)/jre/lib/ext mkdir -p $(BUILD_DEBUG_JRE_DIR)/lib/ext -if ENABLE_PULSE_JAVA - cp -pPRf $(PULSE_JAVA_NATIVE_BUILDDIR)/libpulse-java.so \ - $(BUILD_DEBUG_SDK_DIR)/jre/lib/$(INSTALL_ARCH_DIR) - cp -pPRf $(PULSE_JAVA_NATIVE_BUILDDIR)/libpulse-java.so \ - $(BUILD_DEBUG_JRE_DIR)/lib/$(INSTALL_ARCH_DIR) - cp -pPRf pulse-java.jar \ - $(BUILD_DEBUG_SDK_DIR)/jre/lib/ext - cp -pPRf pulse-java.jar \ - $(BUILD_DEBUG_JRE_DIR)/lib/ext - (cd $(PULSE_JAVA_JAVA_SRCDIR) && \ - $(ZIP) -qur $(BUILD_DEBUG_SDK_DIR)/src.zip org ) -endif if ZERO_BUILD printf -- '-zero ALIASED_TO -server\n' >> $(BUILD_DEBUG_JRE_ARCH_DIR)/jvm.cfg endif @@ -1901,68 +1847,6 @@ clean-icedtea-stage1: clean-check-crypto-boot clean-add-archive-boot rm -f stamps/icedtea-stage1.stamp -# PulseAudio based mixer -# (pulse-java) -if ENABLE_PULSE_JAVA - -stamps/pulse-java.stamp: stamps/pulse-java-jar.stamp $(PULSE_JAVA_NATIVE_BUILDDIR)/libpulse-java.so - mkdir -p stamps - touch $@ - -stamps/pulse-java-class.stamp: $(INITIAL_BOOTSTRAP_LINK_STAMP) - mkdir -p $(PULSE_JAVA_CLASS_DIR) - (cd $(PULSE_JAVA_JAVA_SRCDIR); \ - $(BOOT_DIR)/bin/javac $(IT_JAVACFLAGS) -d $(PULSE_JAVA_CLASS_DIR) \ - -bootclasspath $(RUNTIME) org/classpath/icedtea/pulseaudio/*.java \ - ) - cp -r $(PULSE_JAVA_JAVA_SRCDIR)/META-INF $(PULSE_JAVA_CLASS_DIR) - chmod -R ug+w $(PULSE_JAVA_CLASS_DIR)/META-INF - mkdir -p stamps - touch $@ - -stamps/pulse-java-jar.stamp: stamps/pulse-java-class.stamp - $(BOOT_DIR)/bin/jar cf pulse-java.jar -C $(PULSE_JAVA_CLASS_DIR) .; - mkdir -p stamps - touch $@ - -stamps/pulse-java-headers.stamp: stamps/pulse-java-class.stamp - mkdir -p $(PULSE_JAVA_NATIVE_BUILDDIR) - $(BOOT_DIR)/bin/javah -d $(PULSE_JAVA_NATIVE_BUILDDIR) -classpath $(PULSE_JAVA_CLASS_DIR) \ - org.classpath.icedtea.pulseaudio.EventLoop ; - $(BOOT_DIR)/bin/javah -d $(PULSE_JAVA_NATIVE_BUILDDIR) -classpath $(PULSE_JAVA_CLASS_DIR) \ - org.classpath.icedtea.pulseaudio.Stream - $(BOOT_DIR)/bin/javah -d $(PULSE_JAVA_NATIVE_BUILDDIR) -classpath $(PULSE_JAVA_CLASS_DIR) \ - org.classpath.icedtea.pulseaudio.Operation - $(BOOT_DIR)/bin/javah -d $(PULSE_JAVA_NATIVE_BUILDDIR) -classpath $(PULSE_JAVA_CLASS_DIR) \ - org.classpath.icedtea.pulseaudio.PulseAudioSourcePort - $(BOOT_DIR)/bin/javah -d $(PULSE_JAVA_NATIVE_BUILDDIR) -classpath $(PULSE_JAVA_CLASS_DIR) \ - org.classpath.icedtea.pulseaudio.PulseAudioTargetPort - $(BOOT_DIR)/bin/javah -d $(PULSE_JAVA_NATIVE_BUILDDIR) -classpath $(PULSE_JAVA_CLASS_DIR) \ - -J-Xbootclasspath/p:$(PULSE_JAVA_CLASS_DIR) org.classpath.icedtea.pulseaudio.ContextEvent; - mkdir -p stamps - touch $@ - -$(PULSE_JAVA_NATIVE_BUILDDIR)/%.o: $(PULSE_JAVA_NATIVE_SRCDIR)/%.c stamps/pulse-java-headers.stamp - $(CC) $(IT_CFLAGS) -fPIC -I$(BOOT_DIR)/include/linux -I$(BOOT_DIR)/include \ - -I$(PULSE_JAVA_NATIVE_BUILDDIR) -o $@ -c $< - -$(PULSE_JAVA_NATIVE_BUILDDIR)/libpulse-java.so: $(PULSE_JAVA_NATIVE_OBJECTS) - $(CC) $(LDFLAGS) -shared $(PULSE_JAVA_NATIVE_OBJECTS) $(LIBPULSE_LIBS) \ - -o $(PULSE_JAVA_NATIVE_BUILDDIR)/libpulse-java.so - -endif - -clean-pulse-java: - rm -rf $(PULSE_JAVA_NATIVE_BUILDDIR) - rm -rf $(PULSE_JAVA_CLASS_DIR) - rm -f pulse-java.jar - if [ -e $(PULSE_JAVA_BUILDDIR) ]; then \ - rmdir $(PULSE_JAVA_BUILDDIR) ; \ - fi - rm -f stamps/pulse-java*.stamp - -# end of pulse-java - # JamVM stamps/jamvm.stamp: $(OPENJDK_TREE) @@ -2651,8 +2535,6 @@ patch-fsg: stamps/patch-fsg.stamp -pulse-java: $(PULSE_JAVA_TARGET) - remove-intree-libraries: stamps/remove-intree-libraries.stamp sanitise-openjdk: stamps/sanitise-openjdk.stamp diff -r 8f185d6f0164 -r e5d122ba61c0 NEWS --- a/NEWS Mon Oct 03 16:35:35 2011 +0200 +++ b/NEWS Wed Mar 02 17:03:51 2016 +0000 @@ -52,6 +52,7 @@ - PR1377: Forwardport javac detection / usability test from IcedTea 2.x - PR1379: Add build support for Zero AArch64 - PR1413: Undefined reference to libz during link of unpack200 + - PR1741: Break PulseAudio provider out into IcedTea-Sound - PR1766: Expand architecture support - PR1774: Support GIF lib v5 - PR1774: Correct #ifdef to #if diff -r 8f185d6f0164 -r e5d122ba61c0 configure.ac --- a/configure.ac Mon Oct 03 16:35:35 2011 +0200 +++ b/configure.ac Wed Mar 02 17:03:51 2016 +0000 @@ -64,14 +64,6 @@ AC_CHECK_PROG(XVFB_RUN_CMD, xvfb-run, [xvfb-run -a -e xvfb-errors], []) AC_SUBST(XVFB_RUN_CMD) -AC_MSG_CHECKING([whether to include PulseAudio support]) -AC_ARG_ENABLE([pulse-java], - [AS_HELP_STRING([--enable-pulse-java], - [Enable pulse-java - an audio mixer spi that uses PulseAudio])], - [enable_pulse_java="${enableval}"], [enable_pulse_java="no"]) -AM_CONDITIONAL(ENABLE_PULSE_JAVA, test "x${enable_pulse_java}" = "xyes") -AC_MSG_RESULT(${enable_pulse_java}) - AC_MSG_CHECKING([whether to build documentation]) AC_ARG_ENABLE([docs], [AS_HELP_STRING([--disable-docs], @@ -316,20 +308,6 @@ AC_SUBST(ALSA_LIBS) fi -if test "x${enable_pulse_java}" = "xyes" -then - dnl Check for pulseaudio libraries. - PKG_CHECK_MODULES(LIBPULSE,[libpulse >= 0.9.11],[LIBPULSE_FOUND=yes] - ,[LIBPULSE_FOUND=no]) - if test "x${LIBPULSE_FOUND}" = xno - then - AC_MSG_ERROR([Could not find pulseaudio>=0.9.11 libraries - \ - Try installing pulseaudio-libs-devel>=0.9.11.]) - fi - AC_SUBST(LIBPULSE_CFLAGS) - AC_SUBST(LIBPULSE_LIBS) -fi - if test "x${ZERO_BUILD_TRUE}" = x || test "x${ADD_ZERO_BUILD_TRUE}" = x; then dnl Check for libffi headers and libraries. PKG_CHECK_MODULES(LIBFFI, libffi,[LIBFFI_FOUND=yes],[LIBFFI_FOUND=no]) diff -r 8f185d6f0164 -r e5d122ba61c0 patches/pulse-soundproperties.patch --- a/patches/pulse-soundproperties.patch Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ ---- openjdk/jdk/src/share/lib/sound.properties 2008-08-28 04:15:18.000000000 -0400 -+++ openjdk/jdk/src/share/lib/sound.properties 2008-10-03 16:59:21.000000000 -0400 -@@ -37,3 +37,13 @@ - # Specify the default Receiver by provider and name: - # javax.sound.midi.Receiver=com.sun.media.sound.MidiProvider#SunMIDI1 - # -+ -+# javax.sound.sampled.Clip=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider -+# javax.sound.sampled.Port=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider -+# javax.sound.sampled.SourceDataLine=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider -+# javax.sound.sampled.TargetDataLine=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider -+ -+javax.sound.sampled.Clip=com.sun.media.sound.DirectAudioDeviceProvider -+javax.sound.sampled.Port=com.sun.media.sound.PortMixerProvider -+javax.sound.sampled.SourceDataLine=com.sun.media.sound.DirectAudioDeviceProvider -+javax.sound.sampled.TargetDataLine=com.sun.media.sound.DirectAudioDeviceProvider diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/COPYING --- a/pulseaudio/COPYING Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/README --- a/pulseaudio/README Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -What is this? -An audio SPI implementation for java that uses PulseAudio as a mixer -(so as a bonus you get all of the ear candy that PulseAudio provides) - -How To Build? - - autoreconf && ./configure && ant && make - -Note: Building requires PulseAudio 0.9.12 and java-devel etc.. - -How To Run the Tests? - -After building, do: - - ant test - - (a few tests might fail; they test the networking capabilities of PulseAudio - -Where does it come from? -All of the code was written by the authors - -The sound files new.wav and logout.wav were taken from -http://websvn.kde.org/branches/KDE/4.0/kdeartwork/sounds/ (and renamed). -They are licensed by the copyright holders as GPLv2. - -The sound file error.wav is part of gnome-audio -http://ftp.gnome.org/pub/gnome/sources/gnome-audio/2.22/gnome-audio-2.22.2.tar.bz2 -It is licensed under the LGPL by the copyright holders. diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/META-INF/services/javax.sound.sampled.spi.MixerProvider --- a/pulseaudio/src/java/META-INF/services/javax.sound.sampled.spi.MixerProvider Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -# Providers of sound mixers - -org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextEvent.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextEvent.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* ContextEvent.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.util.Arrays; - -/** - * This class encapsulates a change in the PulseAudio's connection context. - * - * When this event is fired, something has happened to the connection of this - * program to the PulseAudio server. - */ -class ContextEvent { - // There are certain enumerations from pulse audio that we need to use in - // the java side. For all of these, we declare static longs in the proper - // java classes and we use static native methods to initialize them to - // the values used by pulse audio. This makes us immune to changes in - // the integer values of the enum symbols in pulse audio. - /** - * Basically, what is the new state of the context - * These will be initialized to the proper values in the JNI. - */ - static long UNCONNECTED = -1, - CONNECTING = -1, - AUTHORIZING = -1, - SETTING_NAME = -1, - READY = -1, - FAILED = -1, - TERMINATED = -1; - - private static native void init_constants(); - - static { - SecurityWrapper.loadNativeLibrary(); - init_constants(); - } - - /** - * Throws an IllegalStateException if value is not one of the above - * context events. We do this for all pulse audio enumerations that - * we need to use in the java side. If pulse audio decides to add - * new events/states, we need to add them to the classes. The exception - * will let us know. - * return the input if there is no error - * - * @param value is the context event to be checked against one of the known - * events. - * @return value if it is a known event. Otherwise throw an exception. - */ - public static long checkNativeEnumReturn(long value) { - if (!Arrays.asList( - UNCONNECTED, CONNECTING, AUTHORIZING, SETTING_NAME, - READY, FAILED, TERMINATED - ).contains(value)) { - throw new IllegalStateException("Illegal constant for ContextEvent: " + value); - } - return value; - } - - private long type; - - public ContextEvent(long type) { - this.type = checkNativeEnumReturn(type); - } - - public long getType() { - return type; - } -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextListener.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextListener.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* ContextListener.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -/** - * This interface specifies a listener for a change in PulseAudio's context state - * eg: the connection to the server becomes ready, fails or ends. - * - */ - -interface ContextListener { - - void update(ContextEvent e); - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Debug.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Debug.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* EventLoop.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -/** - * - * A simple debugging class. Set the debugging level through the system property - * pulseaudio.debugLevel=. Level is one of Verbose, Debug, Info, Warning, - * Error or None - * - * and then do DebugLevel.println(level, string) and so on - * - */ - -class Debug { - - enum DebugLevel { - Verbose, Debug, Info, Warning, Error, None - } - - private static DebugLevel currentDebugLevel = DebugLevel.None; - - static { - // System.out.println("PulseAudio: initializing Debug"); - - String systemSetting; - try { - systemSetting = System.getProperty("pulseaudio.debugLevel"); - } catch (SecurityException e) { - // sigh, we cant read that property - systemSetting = null; - } - - DebugLevel wantedLevel; - try { - wantedLevel = DebugLevel.valueOf(systemSetting); - - } catch (IllegalArgumentException e) { - wantedLevel = DebugLevel.Info; - } catch (NullPointerException e) { - wantedLevel = DebugLevel.None; - } - - currentDebugLevel = wantedLevel; - println(DebugLevel.Info, "Using debug level: " + currentDebugLevel); - } - - static void println(String string) { - println(DebugLevel.Info, string); - } - - static void print(DebugLevel level, String string) { - int result = level.compareTo(currentDebugLevel); - if (result >= 0) { - if (level.compareTo(DebugLevel.Error) >= 0) { - System.err.print(string); - } else { - System.out.print(string); - } - } else { - // do nothing - } - } - - static void println(DebugLevel level, String string) { - - int result = level.compareTo(currentDebugLevel); - if (result >= 0) { - if (level.compareTo(DebugLevel.Error) >= 0) { - System.err.println("DEBUG: pulse-java: " + string); - } else { - System.out.println("DEBUG: pulse-java: " + string); - } - } else { - // do nothing - } - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/EventLoop.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/EventLoop.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,246 +0,0 @@ -/* EventLoop.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.util.ArrayList; -import java.util.List; - -import org.classpath.icedtea.pulseaudio.ContextEvent; -import org.classpath.icedtea.pulseaudio.Debug.DebugLevel; - -/** - * This class wraps pulseaudio's event loop. It also holds the lock used in the - * rest of pulse-java - */ - -final class EventLoop implements Runnable { - - /* - * any methods that can obstruct the behaviour of pa_mainloop should run - * synchronized - */ - - /* - * the threadLock object is the object used for synchronizing the - * non-thread-safe operations of pulseaudio's c api - */ - final Object threadLock = new Object(); - - private static EventLoop instance = null; - - private List contextListeners; - // private List lines; - private String appName; - private String serverString; - - private long status; - // private boolean eventLoopIsRunning = false; - - private List targetPortNameList = new ArrayList(); - private List sourcePortNameList = new ArrayList(); - - /* - * JNI stuff - * - * Do not synchronize the individual functions, synchronize - * block/method/lines around the call - */ - - private native void native_setup(String appName, String server); - - private native int native_iterate(int timeout); - - private native void native_shutdown(); - - /* - * These fields hold pointers - */ - private byte[] contextPointer; - private byte[] mainloopPointer; - - static { - SecurityWrapper.loadNativeLibrary(); - } - - private EventLoop() { - contextListeners = new ArrayList(); - } - - synchronized static EventLoop getEventLoop() { - if (instance == null) { - instance = new EventLoop(); - } - return instance; - } - - void setAppName(String appName) { - this.appName = appName; - } - - void setServer(String serverString) { - this.serverString = serverString; - } - - @Override - public void run() { - native_setup(this.appName, this.serverString); - - Debug.println(DebugLevel.Info, "Eventloop.run(): eventloop starting"); - - /* - * Perhaps this loop should be written in C doing a Java to C call on - * every iteration of the loop might be slow - */ - while (true) { - synchronized (threadLock) { - // timeout is in milliseconds - // timout = 0 means dont block - native_iterate(100); - - if (Thread.interrupted()) { - native_shutdown(); - - // clean up the listeners - synchronized (contextListeners) { - contextListeners.clear(); - } - - Debug.println(DebugLevel.Info, - "EventLoop.run(): event loop terminated"); - - return; - - } - } - } - - } - - void addContextListener(ContextListener contextListener) { - synchronized (contextListeners) { - contextListeners.add(contextListener); - } - } - - void removeContextListener(ContextListener contextListener) { - synchronized (contextListeners) { - contextListeners.remove(contextListener); - } - } - - long getStatus() { - return this.status; - } - - void update(long status) { - synchronized (threadLock) { - // System.out.println(this.getClass().getName() - // + ".update() called! status = " + status); - this.status = status; - fireEvent(new ContextEvent(status)); - } - - if (status == ContextEvent.FAILED) { - Debug.println(DebugLevel.Warning, - "EventLoop.update(): Context failed"); - } - } - - private void fireEvent(final ContextEvent e) { - // System.out.println(this.getClass().getName() + "firing event: " - // + e.getType().toString()); - - synchronized (contextListeners) { - // System.out.println(contextListeners.size()); - for (ContextListener listener : contextListeners) { - listener.update(e); - } - } - - } - - byte[] getContextPointer() { - return contextPointer; - } - - byte[] getMainLoopPointer() { - return mainloopPointer; - } - - private native byte[] nativeUpdateTargetPortNameList(); - - private native byte[] nativeUpdateSourcePortNameList(); - - synchronized List updateTargetPortNameList() { - targetPortNameList = new ArrayList(); - Operation op; - synchronized (this.threadLock) { - op = new Operation(nativeUpdateTargetPortNameList()); - } - - op.waitForCompletion(); - - assert (op.getState() == Operation.DONE); - - op.releaseReference(); - return targetPortNameList; - } - - protected synchronized List updateSourcePortNameList() { - sourcePortNameList = new ArrayList(); - Operation op; - synchronized (this.threadLock) { - op = new Operation(nativeUpdateSourcePortNameList()); - } - - op.waitForCompletion(); - - assert (op.getState() == Operation.DONE); - - op.releaseReference(); - return sourcePortNameList; - } - - public void source_callback(String name) { - sourcePortNameList.add(name); - } - - public void sink_callback(String name) { - targetPortNameList.add(name); - } -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Operation.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Operation.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -/* Operation.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.util.Arrays; - -/** - * Encapsulates a pa_operation object - * - * This is really needed only so that we can deallocate the reference counted - * object. Any time a function returns an Operation object, the reference has - * been incremented. The object wont be freed unless a releaseReference() is - * done. - * - * Please see the pulseaudio api docs for more information on a pa_opreation - * object - * - * - * - */ - -class Operation { - - private byte[] operationPointer; - private EventLoop eventLoop; - - // These should never be written to in java. They will be initialized - // properly in native code. - public static long RUNNING = -1, - DONE = -1, - CANCELLED = -1; - - private static native void init_constants(); - - static { - SecurityWrapper.loadNativeLibrary(); - init_constants(); - } - - // If value is not one of RUNNING, DONE, CANCELLED, throw an - // IllegalStateException. Otherwise return the input. - private static long checkNativeOperationState(long value) { - if (!Arrays.asList(RUNNING, DONE, CANCELLED).contains(value)) { - throw new IllegalStateException("Unknown operation state: " + value); - } - return value; - } - - private native void native_ref(); - - private native void native_unref(); - - private native long native_get_state(); - - Operation(byte[] operationPointer) { - assert (operationPointer != null); - this.operationPointer = operationPointer; - this.eventLoop = EventLoop.getEventLoop(); - } - - @Override - protected void finalize() throws Throwable { - // might catch operations which havent been released - assert (operationPointer == null); - super.finalize(); - } - - /** - * Increase reference count by 1 - */ - void addReference() { - assert (operationPointer != null); - synchronized (eventLoop.threadLock) { - native_ref(); - } - } - - /** - * Decrease reference count by 1. If the count reaches 0, object will be freed - */ - void releaseReference() { - assert (operationPointer != null); - synchronized (eventLoop.threadLock) { - native_unref(); - } - operationPointer = null; - } - - // FIXME broken function - boolean isNull() { - if (operationPointer == null) { - return true; - } - return false; - } - - long getState() { - assert (operationPointer != null); - synchronized (eventLoop.threadLock) { - return checkNativeOperationState(native_get_state()); - } - } - - /** - * Block until the operation has completed - * - */ - void waitForCompletion() { - assert (operationPointer != null); - - boolean interrupted = false; - do { - synchronized (eventLoop.threadLock) { - if (getState() == DONE) { - return; - } - try { - eventLoop.threadLock.wait(); - } catch (InterruptedException e) { - // ingore the interrupt for now - interrupted = true; - } - } - } while (getState() != DONE); - - // let the caller know about the interrupt - if (interrupted) { - Thread.currentThread().interrupt(); - } - } -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,574 +0,0 @@ -/* PulseAudioClip.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.io.IOException; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Clip; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineUnavailableException; - -import org.classpath.icedtea.pulseaudio.Debug.DebugLevel; -import org.classpath.icedtea.pulseaudio.Stream.WriteListener; - -public final class PulseAudioClip extends PulseAudioDataLine implements Clip, - PulseAudioPlaybackLine { - - private byte[] data = null; - - // these are frame indices. so counted from 0 - // the current frame index - private int currentFrame = 0; - - // total number of frames in this clip - private int frameCount = 0; - - // the starting frame of the loop - private int startFrame = 0; - // the ending frame of the loop - private int endFrame = 0; - - public static final String DEFAULT_CLIP_NAME = "Audio Clip"; - - private Object clipLock = new Object(); - private int loopsLeft = 0; - - // private Semaphore clipSemaphore = new Semaphore(1); - - /** - * This thread runs - * - */ - private final class ClipThread extends Thread { - @Override - public void run() { - - /* - * The while loop below only works with LOOP_CONTINUOUSLY because we - * abuse the fact that loopsLeft's initial value is -1 - * (=LOOP_CONTINUOUSLY) and it keeps on going lower without hitting - * 0. So do a sanity check - */ - if (Clip.LOOP_CONTINUOUSLY != -1) { - throw new UnsupportedOperationException( - "LOOP_CONTINUOUSLY has changed; things are going to break"); - } - - while (true) { - writeFrames(currentFrame, endFrame + 1); - if (Thread.interrupted()) { - // Thread.currentThread().interrupt(); - // System.out.println("returned from interrupted - // writeFrames"); - break; - } - - // if loop(0) has been called from the mainThread, - // wait until loopsLeft has been set - if (loopsLeft == 0) { - // System.out.println("Reading to the end of the file"); - // System.out.println("endFrame: " + endFrame); - writeFrames(endFrame, getFrameLength()); - break; - } else { - synchronized (clipLock) { - currentFrame = startFrame; - if (loopsLeft != Integer.MIN_VALUE) { - loopsLeft--; - } - } - } - - } - - // drain - Operation operation; - - synchronized (eventLoop.threadLock) { - operation = stream.drain(); - } - - operation.waitForCompletion(); - operation.releaseReference(); - - } - } - - private ClipThread clipThread; - - private void writeFrames(int startingFrame, int lastFrame) { - - WriteListener writeListener = new WriteListener() { - @Override - public void update() { - synchronized (eventLoop.threadLock) { - eventLoop.threadLock.notifyAll(); - } - } - }; - - stream.addWriteListener(writeListener); - - Debug.println(DebugLevel.Verbose, - "PulseAudioClip$ClipThread.writeFrames(): Writing"); - - int remainingFrames = lastFrame - startingFrame - 1; - while (remainingFrames > 0) { - synchronized (eventLoop.threadLock) { - int availableSize; - - do { - availableSize = stream.getWritableSize(); - if (availableSize < 0) { - Thread.currentThread().interrupt(); - stream.removeWriteListener(writeListener); - return; - } - if (availableSize == 0) { - try { - eventLoop.threadLock.wait(); - } catch (InterruptedException e) { - // System.out - // .println("interrupted while waiting for - // getWritableSize"); - // clean up and return - Thread.currentThread().interrupt(); - stream.removeWriteListener(writeListener); - return; - } - } - - } while (availableSize == 0); - - int framesToWrite = Math.min(remainingFrames, availableSize - / getFormat().getFrameSize()); - stream.write(data, currentFrame * getFormat().getFrameSize(), - framesToWrite * getFormat().getFrameSize()); - remainingFrames -= framesToWrite; - currentFrame += framesToWrite; - framesSinceOpen += framesToWrite; - if (Thread.interrupted()) { - Thread.currentThread().interrupt(); - break; - } - // System.out.println("remaining frames" + remainingFrames); - // System.out.println("currentFrame: " + currentFrame); - // System.out.println("framesSinceOpen: " + framesSinceOpen); - } - } - - stream.removeWriteListener(writeListener); - } - - PulseAudioClip(AudioFormat[] formats, AudioFormat defaultFormat) { - this.supportedFormats = formats; - this.defaultFormat = defaultFormat; - this.currentFormat = defaultFormat; - this.streamName = DEFAULT_CLIP_NAME; - - clipThread = new ClipThread(); - - } - - @Override - protected void connectLine(int bufferSize, Stream masterStream) - throws LineUnavailableException { - StreamBufferAttributes bufferAttributes = new StreamBufferAttributes( - bufferSize, bufferSize / 4, bufferSize / 8, - ((bufferSize / 10) > 100 ? bufferSize / 10 : 100), 0); - - if (masterStream != null) { - synchronized (eventLoop.threadLock) { - stream.connectForPlayback(Stream.DEFAULT_DEVICE, - bufferAttributes, masterStream.getStreamPointer()); - } - } else { - synchronized (eventLoop.threadLock) { - stream.connectForPlayback(Stream.DEFAULT_DEVICE, - bufferAttributes, null); - } - } - } - - @Override - public int available() { - return 0; // a clip always returns 0 - } - - @Override - public void close() { - - if (!isOpen) { - throw new IllegalStateException("line already closed"); - } - - clipThread.interrupt(); - - try { - clipThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - currentFrame = 0; - framesSinceOpen = 0; - - PulseAudioMixer mixer = PulseAudioMixer.getInstance(); - mixer.removeSourceLine(this); - - super.close(); - - Debug.println(DebugLevel.Verbose, "PulseAudioClip.close(): " - + "Clip closed"); - - } - - /* - * - * drain() on a Clip should block until the entire clip has finished playing - * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4732218 - */ - @Override - public void drain() { - if (!isOpen) { - throw new IllegalStateException("line not open"); - } - - while (clipThread != null && clipThread.isAlive()) { - try { - clipThread.join(); - } catch (InterruptedException e) { - // ignore - } - } - - Operation operation; - - synchronized (eventLoop.threadLock) { - operation = stream.drain(); - } - - operation.waitForCompletion(); - operation.releaseReference(); - - } - - @Override - public void flush() { - if (!isOpen) { - throw new IllegalStateException("line not open"); - } - - Operation operation; - synchronized (eventLoop.threadLock) { - operation = stream.flush(); - operation.waitForCompletion(); - } - operation.releaseReference(); - - } - - @Override - public int getFrameLength() { - if (!isOpen) { - return AudioSystem.NOT_SPECIFIED; - } - - return frameCount; - } - - @Override - public int getFramePosition() { - if (!isOpen) { - throw new IllegalStateException("Line not open"); - } - synchronized (clipLock) { - return (int) framesSinceOpen; - } - } - - @Override - public long getLongFramePosition() { - if (!isOpen) { - throw new IllegalStateException("Line not open"); - } - - synchronized (clipLock) { - return framesSinceOpen; - } - } - - @Override - public long getMicrosecondLength() { - if (!isOpen) { - return AudioSystem.NOT_SPECIFIED; - } - synchronized (clipLock) { - return (long) (frameCount / currentFormat.getFrameRate() * SECONDS_TO_MICROSECONDS); - } - } - - @Override - public long getMicrosecondPosition() { - if (!isOpen) { - throw new IllegalStateException("Line not open"); - } - - synchronized (clipLock) { - return (long) (framesSinceOpen / currentFormat.getFrameRate() * SECONDS_TO_MICROSECONDS); - } - } - - @Override - public void loop(int count) { - if (!isOpen) { - throw new IllegalStateException("Line not open"); - } - - if (count < 0 && count != LOOP_CONTINUOUSLY) { - throw new IllegalArgumentException("invalid value for count:" - + count); - } - - if (clipThread.isAlive() && count != 0) { - // Do nothing; behavior not specified by the Java API - return; - } - - super.start(); - - synchronized (clipLock) { - if (currentFrame > endFrame) { - loopsLeft = 0; - } else { - loopsLeft = count; - } - } - if (!clipThread.isAlive()) { - clipThread = new ClipThread(); - clipThread.start(); - } - - } - - @Override - public void open() throws LineUnavailableException { - throw new IllegalArgumentException("open() on a Clip is not allowed"); - } - - @Override - public void open(AudioFormat format, byte[] data, int offset, int bufferSize) - throws LineUnavailableException { - - super.open(format); - this.data = new byte[bufferSize]; - System.arraycopy(data, offset, this.data, 0, bufferSize); - - frameCount = bufferSize / format.getFrameSize(); - currentFrame = 0; - framesSinceOpen = 0; - startFrame = 0; - endFrame = frameCount - 1; - loopsLeft = 0; - - PulseAudioVolumeControl volumeControl = new PulseAudioVolumeControl( - this, eventLoop); - controls.add(volumeControl); - - PulseAudioMixer mixer = PulseAudioMixer.getInstance(); - mixer.addSourceLine(this); - - isOpen = true; - Debug.println(DebugLevel.Verbose, "PulseAudioClip.open(): Clip opened"); - - } - - // FIXME - @Override - public byte[] native_set_volume(float value) { - return stream.native_set_volume(value); - } - - public byte[] native_update_volume() { - return stream.native_update_volume(); - } - - @Override - public float getCachedVolume() { - return stream.getCachedVolume(); - } - - @Override - public void setCachedVolume(float value) { - stream.setCachedVolume(value); - - } - - @Override - public void open(AudioInputStream stream) throws LineUnavailableException, - IOException { - byte[] buffer = new byte[(int) (stream.getFrameLength() * stream - .getFormat().getFrameSize())]; - stream.read(buffer, 0, buffer.length); - - open(stream.getFormat(), buffer, 0, buffer.length); - - } - - @Override - public void setFramePosition(int frames) { - if (!isOpen) { - throw new IllegalStateException("Line not open"); - } - - if (frames < 0 || frames > frameCount) { - throw new IllegalArgumentException("incorreft frame value"); - } - - synchronized (clipLock) { - currentFrame = frames; - } - - } - - @Override - public void setLoopPoints(int start, int end) { - if (!isOpen) { - throw new IllegalStateException("Line not open"); - } - - if (end == -1) { - end = frameCount - 1; - } - - if (end < start) { - throw new IllegalArgumentException( - "ending point must be greater than or equal to the starting point"); - } - - if (start < 0) { - throw new IllegalArgumentException( - "starting point must be greater than or equal to 0"); - } - - synchronized (clipLock) { - startFrame = start; - endFrame = end; - } - - } - - @Override - public void setMicrosecondPosition(long microseconds) { - if (!isOpen) { - throw new IllegalStateException("Line not open"); - } - - float frameIndex = microseconds * currentFormat.getFrameRate() / SECONDS_TO_MICROSECONDS; - - /* make frameIndex positive */ - while (frameIndex < 0) { - frameIndex += frameCount; - } - - /* frameIndex is in the range [0, frameCount-1], inclusive */ - frameIndex = frameIndex % frameCount; - - synchronized (clipLock) { - currentFrame = (int) frameIndex; - } - - } - - @Override - public void start() { - if (isStarted) { - return; - } - - super.start(); - - if (!clipThread.isAlive()) { - synchronized (clipLock) { - loopsLeft = 0; - } - clipThread = new ClipThread(); - clipThread.start(); - } - - } - - @Override - public void stop() { - if (!isOpen) { - throw new IllegalStateException("Line not open"); - } - - /* do what start does and ignore if called at the wrong time */ - if (!isStarted) { - return; - } - - if (clipThread.isAlive()) { - clipThread.interrupt(); - } - try { - clipThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - synchronized (clipLock) { - loopsLeft = 0; - } - - super.stop(); - - } - - @Override - public Line.Info getLineInfo() { - return new DataLine.Info(Clip.class, supportedFormats, - StreamBufferAttributes.MIN_VALUE, - StreamBufferAttributes.MAX_VALUE); - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,498 +0,0 @@ -/* PulseAudioClip.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.util.concurrent.Semaphore; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineUnavailableException; - -import org.classpath.icedtea.pulseaudio.Stream.WriteListener; - -/** - * - * This class contains code that is used by Clip, SourceDataLine and - * TargetDataLine - * - */ -abstract class PulseAudioDataLine extends PulseAudioLine implements DataLine { - - protected static final int DEFAULT_BUFFER_SIZE = StreamBufferAttributes.SANE_DEFAULT; - - // override this to set the stream name - protected String streamName; - - // true between start() and stop() - protected boolean isStarted = false; - - // true between a started and an underflow callback - protected boolean dataWritten = false; - - // true if a stream has been paused - // protected boolean isPaused = false; - - protected AudioFormat[] supportedFormats = null; - protected AudioFormat currentFormat = null; - protected AudioFormat defaultFormat = null; - protected boolean sendEvents = true; - - // the total number of frames played since this line was opened - protected long framesSinceOpen = 0; - - protected EventLoop eventLoop = null; - protected Semaphore semaphore = new Semaphore(0); - protected Stream stream; - boolean writeInterrupted = false; - - protected void open(AudioFormat format, int bufferSize) - throws LineUnavailableException { - - if (isOpen()) { - throw new IllegalStateException("Line is already open"); - } - - PulseAudioMixer mixer = PulseAudioMixer.getInstance(); - if (!mixer.isOpen()) { - mixer.open(); - } - - eventLoop = EventLoop.getEventLoop(); - - createStream(format); - addStreamListeners(); - connect(null, bufferSize); - } - - private void createStream(AudioFormat format) - throws LineUnavailableException { - - for (AudioFormat myFormat : supportedFormats) { - if (format.matches(myFormat)) { - /* - * A few issues with format: - * - * To match: SAME encoding: safe because its a java enum. SAME - * number of channels: safe because myFormat has specific - * values. SAME bits per sample (aka sampleSize) and bytes per - * frame (aka frameSize): safe because myFormat has specific - * values. SAME sample rate: _not_ safe because myFormat uses - * AudioSystem.NOT_SPECIFIED. SAME frame rate: safe because we - * _ignore_ it completely ;) - */ - - float sampleRate = format.getSampleRate(); - if (sampleRate == (float) AudioSystem.NOT_SPECIFIED) { - /* pick a random sample rate */ - sampleRate = 44100.0f; - } - - String formatString = (String) myFormat - .getProperty(PulseAudioMixer.PULSEAUDIO_FORMAT_KEY); - synchronized (eventLoop.threadLock) { - - stream = new Stream(eventLoop.getContextPointer(), - streamName, Stream.Format.valueOf(formatString), - (int) sampleRate, myFormat.getChannels()); - - } - currentFormat = format; - isOpen = true; - } - } - - if (!isOpen()) { - throw new IllegalArgumentException("Invalid format"); - } - - // System.out.println("Stream " + stream + " created"); - - } - - /** - * This method adds the listeners used to find out when the stream has - * connected/disconnected etc to the actual stream. - */ - private void addStreamListeners() { - Stream.StateListener openCloseListener = new Stream.StateListener() { - - @Override - public void update() { - synchronized (eventLoop.threadLock) { - - /* - * Note the order: first we notify all the listeners, and - * then return. this means no race conditions when the - * listeners are removed before they get called by close - * - * eg: - * - * line.close(); line.removeLineListener(listener) - * - * the listener is guaranteed to have run - */ - - if (stream.getState() == Stream.STATE_READY) { - if (sendEvents) { - fireLineEvent(new LineEvent( - PulseAudioDataLine.this, - LineEvent.Type.OPEN, framesSinceOpen)); - } - semaphore.release(); - - } else if (stream.getState() == Stream.STATE_TERMINATED - || stream.getState() == Stream.STATE_FAILED) { - if (sendEvents) { - fireLineEvent((new LineEvent( - PulseAudioDataLine.this, - LineEvent.Type.CLOSE, framesSinceOpen))); - } - semaphore.release(); - } - } - } - }; - - stream.addStateListener(openCloseListener); - - Stream.UnderflowListener stoppedListener = new Stream.UnderflowListener() { - @Override - public void update() { - dataWritten = false; - - // always send a STOP event on an underflow (assumption: - // an underflow can't happen while the stream is corked) - fireLineEvent(new LineEvent(PulseAudioDataLine.this, - LineEvent.Type.STOP, framesSinceOpen)); - } - }; - stream.addUnderflowListener(stoppedListener); - - Stream.PlaybackStartedListener startedListener = new Stream.PlaybackStartedListener() { - @Override - public void update() { - if (!dataWritten) { - fireLineEvent(new LineEvent(PulseAudioDataLine.this, - LineEvent.Type.START, framesSinceOpen)); - synchronized (PulseAudioDataLine.this) { - PulseAudioDataLine.this.notifyAll(); - } - } - dataWritten = true; - - } - }; - - stream.addPlaybackStartedListener(startedListener); - - WriteListener writeNotifier = new WriteListener() { - - @Override - public void update() { - synchronized (eventLoop.threadLock) { - eventLoop.threadLock.notifyAll(); - } - } - - }; - stream.addWriteListener(writeNotifier); - - Stream.CorkListener corkListener = new Stream.CorkListener() { - - @Override - public void update() { - synchronized (eventLoop.threadLock) { - eventLoop.threadLock.notifyAll(); - } - } - - }; - stream.addCorkListener(corkListener); - } - - private void connect(Stream masterStream, int bufferSize) - throws LineUnavailableException { - - try { - synchronized (eventLoop.threadLock) { - connectLine(bufferSize, masterStream); - } - } catch (LineUnavailableException e) { - // error connecting to the server! - // stream.removePlaybackStartedListener(startedListener); - // stream.removeUnderflowListener(stoppedListener); - // stream.removeStateListener(openCloseListener); - stream.free(); - stream = null; - throw e; - - } - try { - semaphore.acquire(); - synchronized (eventLoop.threadLock) { - if (stream.getState() != Stream.STATE_READY) { - stream.disconnect(); - stream.free(); - throw new LineUnavailableException( - "unable to obtain a line"); - } - } - } catch (InterruptedException e) { - throw new LineUnavailableException("unable to prepare stream"); - } - } - - protected void open(AudioFormat format) throws LineUnavailableException { - open(format, DEFAULT_BUFFER_SIZE); - - } - - @Override - public void open() throws LineUnavailableException { - assert (defaultFormat != null); - open(defaultFormat, DEFAULT_BUFFER_SIZE); - } - - @Override - public void close() { - - if (!isOpen()) { - // For whatever reason, we are being asked to close - // a line that is not even open. - return; - } - - synchronized (eventLoop.threadLock) { - stream.disconnect(); - } - - try { - semaphore.acquire(); - } catch (InterruptedException e) { - throw new RuntimeException("unable to prepare stream"); - } - - synchronized (eventLoop.threadLock) { - stream.free(); - } - - super.close(); - - isStarted = false; - } - - void reconnectforSynchronization(Stream masterStream) - throws LineUnavailableException { - sendEvents = false; - drain(); - - synchronized (eventLoop.threadLock) { - stream.disconnect(); - } - try { - semaphore.acquire(); - } catch (InterruptedException e) { - throw new RuntimeException("unable to prepare stream"); - } - - createStream(getFormat()); - addStreamListeners(); - connect(masterStream, getBufferSize()); - - sendEvents = true; - } - - @Override - public void start() { - if (!isOpen()) { - throw new IllegalStateException( - "Line must be open()ed before it can be start()ed"); - } - - if (isStarted) { - return; - - } - if (dataWritten && (!isStarted)) { - fireLineEvent(new LineEvent(PulseAudioDataLine.this, - LineEvent.Type.START, framesSinceOpen)); - } - - Operation op; - synchronized (eventLoop.threadLock) { - op = stream.unCork(); - } - - op.waitForCompletion(); - op.releaseReference(); - synchronized (this) { - this.notifyAll(); - } - isStarted = true; - - } - - @Override - public synchronized void stop() { - if (!isOpen()) { - // For some reason, we are being asked to stop a line - // that isn't even open. - return; - } - writeInterrupted = true; - if (!isStarted) { - return; - } - - Operation op; - synchronized (eventLoop.threadLock) { - op = stream.cork(); - // if there are no data on the line when stop was called, - // don't send a stop event - if (dataWritten && (isStarted)) { - fireLineEvent(new LineEvent(PulseAudioDataLine.this, - LineEvent.Type.STOP, framesSinceOpen)); - } - } - - op.waitForCompletion(); - op.releaseReference(); - - isStarted = false; - } - - /* - * TODO - * - * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4791152 : - * - * a line is active in between calls to start() and stop(). In that sense, - * active means that the line is ready to take or give data. Running is - * tightly bound to data flow in the line. I.e. when you start a - * SourceDataLine but never write data to it, the line should not be - * running. This also means that a line should become not running on buffer - * underrun/overflow. - * - * - * HOWEVER, the javadocs say the opposite thing! (need help from the jck = - * official spec) - */ - @Override - public boolean isActive() { - return isStarted; - } - - @Override - public boolean isRunning() { - return isStarted && dataWritten; - } - - protected abstract void connectLine(int bufferSize, Stream masterStream) - throws LineUnavailableException; - - public Stream getStream() { - if (!isOpen()) { - throw new IllegalStateException("Line must be open"); - } - - return stream; - } - - @Override - public int getBufferSize() { - if (!isOpen()) { - return DEFAULT_BUFFER_SIZE; - } - return stream.getBufferSize(); - } - - @Override - public AudioFormat getFormat() { - if (!isOpen()) { - return defaultFormat; - } - return currentFormat; - } - - @Override - public float getLevel() { - return AudioSystem.NOT_SPECIFIED; - } - - /** - * - * @param streamName - * the name of this audio stream - */ - public void setName(String streamName) { - if (isOpen()) { - - Operation o; - synchronized (eventLoop.threadLock) { - o = stream.setName(streamName); - } - o.waitForCompletion(); - o.releaseReference(); - - } - - this.streamName = streamName; - - } - - /** - * - * @return the name of this audio stream/clip - */ - public String getName() { - return streamName; - } - - public int getBytesInBuffer() { - Operation o; - synchronized (eventLoop.threadLock) { - o = stream.updateTimingInfo(); - } - o.waitForCompletion(); - o.releaseReference(); - return stream.bytesInBuffer(); - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioLine.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioLine.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* PulseAudioClip.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.util.ArrayList; -import java.util.List; - -import javax.sound.sampled.Control; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.Control.Type; - -abstract class PulseAudioLine implements Line { - - protected List lineListeners = new ArrayList(); - protected List controls = new ArrayList(); - - // true between open() and close(). ie represents when a line has acquire - // resources - protected boolean isOpen = false; - - @Override - public void addLineListener(LineListener listener) { - this.lineListeners.add(listener); - } - - @Override - public void close() { - if (!isOpen()) { - throw new IllegalStateException("Line is not open"); - } - - lineListeners.clear(); - - isOpen = false; - } - - protected void fireLineEvent(LineEvent e) { - for (LineListener lineListener : lineListeners) { - lineListener.update(e); - } - } - - @Override - public Control getControl(Type control) { - if (isOpen()) { - for (Control aControl : controls) { - if (aControl.getType() == control) { - return aControl; - } - } - } - throw new IllegalArgumentException(control.toString() - + " not supported"); - } - - @Override - public Control[] getControls() { - if (!isOpen()) { - return new Control[] {}; - } - - return (Control[]) controls.toArray(new Control[0]); - } - - @Override - public boolean isControlSupported(Type control) { - for (Control myControl : controls) { - //Control.Type's known descendants keep a set of - //static Types. - if (myControl.getType().equals(control)) { - return true; - } - } - return false; - } - - @Override - public boolean isOpen() { - return isOpen; - } - - @Override - public void removeLineListener(LineListener listener) { - lineListeners.remove(listener); - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,792 +0,0 @@ -/* PulseAudioMixer.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Semaphore; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioPermission; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Clip; -import javax.sound.sampled.Control; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; -import javax.sound.sampled.Port; -import javax.sound.sampled.SourceDataLine; -import javax.sound.sampled.TargetDataLine; -import javax.sound.sampled.AudioFormat.Encoding; -import javax.sound.sampled.Control.Type; - -import org.classpath.icedtea.pulseaudio.Debug.DebugLevel; - -public final class PulseAudioMixer implements Mixer { - // singleton - - private Thread eventLoopThread; - - private List sourceLineInfos = new ArrayList(); - private List staticSourceLineInfos = new ArrayList(); - - private List targetLineInfos = new ArrayList(); - private List staticTargetLineInfos = new ArrayList(); - - private static PulseAudioMixer _instance = null; - - private static final String DEFAULT_APP_NAME = "Java"; - static final String PULSEAUDIO_FORMAT_KEY = "PulseAudioFormatKey"; - - private boolean isOpen = false; - - private final List sourceLines = new ArrayList(); - private final List targetLines = new ArrayList(); - - private final List lineListeners = new ArrayList(); - - private PulseAudioMixer() { - - Debug.println(DebugLevel.Verbose, "PulseAudioMixer.PulseAudioMixer(): " - + "Contructing PulseAudioMixer..."); - - AudioFormat[] formats = getSupportedFormats(); - - staticSourceLineInfos.add(new DataLine.Info(SourceDataLine.class, - formats, StreamBufferAttributes.MIN_VALUE, - StreamBufferAttributes.MAX_VALUE)); - staticSourceLineInfos.add(new DataLine.Info(Clip.class, formats, - StreamBufferAttributes.MIN_VALUE, - StreamBufferAttributes.MAX_VALUE)); - - staticTargetLineInfos.add(new DataLine.Info(TargetDataLine.class, - formats, StreamBufferAttributes.MIN_VALUE, - StreamBufferAttributes.MAX_VALUE)); - - refreshSourceAndTargetLines(); - - Debug.println(DebugLevel.Verbose, "PulseAudioMixer.PulseAudioMixer(): " - + "Finished constructing PulseAudioMixer"); - - } - - synchronized public static PulseAudioMixer getInstance() { - if (_instance == null) { - _instance = new PulseAudioMixer(); - } - return _instance; - } - - private AudioFormat[] getSupportedFormats() { - - List supportedFormats = new ArrayList(); - - Map properties; - - /* - * frameSize = sample size (in bytes, not bits) x # of channels - * - * From PulseAudio's sources - * http://git.0pointer.de/?p=pulseaudio.git;a=blob - * ;f=src/pulse/sample.c;h=93da2465f4301e27af4976e82737c3a048124a68;hb= - * 82ea8dde8abc51165a781c69bc3b38034d62d969#l63 - */ - - /* - * technically, PulseAudio supports up to 16 channels, but things get - * interesting with channel maps - * - * PA_CHANNEL_MAP_DEFAULT (=PA_CHANNEL_MAP_AIFF) supports 1,2,3,4,5 or 6 - * channels only - */ - int[] channelSizes = new int[] { 1, 2, 3, 4, 5, 6 }; - - for (int channelSize : channelSizes) { - properties = new HashMap(); - properties.put(PULSEAUDIO_FORMAT_KEY, "PA_SAMPLE_ALAW"); - - int sampleSize = 8; - final AudioFormat PA_SAMPLE_ALAW = new AudioFormat(Encoding.ALAW, // encoding - AudioSystem.NOT_SPECIFIED, // sample rate - sampleSize, // sample size - channelSize, // channels - sampleSize / 8 * channelSize, // frame size - AudioSystem.NOT_SPECIFIED, // frame rate - false, // big endian? - properties); - - supportedFormats.add(PA_SAMPLE_ALAW); - } - - for (int channelSize : channelSizes) { - properties = new HashMap(); - properties.put(PULSEAUDIO_FORMAT_KEY, "PA_SAMPLE_ULAW"); - - int sampleSize = 8; - final AudioFormat PA_SAMPLE_ULAW = new AudioFormat(Encoding.ULAW, // encoding - AudioSystem.NOT_SPECIFIED, // sample rate - sampleSize, // sample size - channelSize, // channels - sampleSize / 8 * channelSize, // frame size - AudioSystem.NOT_SPECIFIED, // frame rate - false, // big endian? - properties); - - supportedFormats.add(PA_SAMPLE_ULAW); - } - - for (int channelSize : channelSizes) { - properties = new HashMap(); - properties.put(PULSEAUDIO_FORMAT_KEY, "PA_SAMPLE_S16BE"); - - int sampleSize = 16; - final AudioFormat PA_SAMPLE_S16BE = new AudioFormat( - Encoding.PCM_SIGNED, // encoding - AudioSystem.NOT_SPECIFIED, // sample rate - sampleSize, // sample size - channelSize, // channels - sampleSize / 8 * channelSize, // frame size - AudioSystem.NOT_SPECIFIED, // frame rate - true, // big endian? - properties); - - supportedFormats.add(PA_SAMPLE_S16BE); - } - - for (int channelSize : channelSizes) { - properties = new HashMap(); - properties.put(PULSEAUDIO_FORMAT_KEY, "PA_SAMPLE_S16LE"); - - int sampleSize = 16; - final AudioFormat A_SAMPLE_S16LE = new AudioFormat( - Encoding.PCM_SIGNED, // encoding - AudioSystem.NOT_SPECIFIED, // sample rate - sampleSize, // sample size - channelSize, // channels - sampleSize / 8 * channelSize, // frame size - AudioSystem.NOT_SPECIFIED, // frame rate - false, // big endian? - properties); - - supportedFormats.add(A_SAMPLE_S16LE); - } - - for (int channelSize : channelSizes) { - properties = new HashMap(); - properties.put(PULSEAUDIO_FORMAT_KEY, "PA_SAMPLE_S32BE"); - - int sampleSize = 32; - final AudioFormat PA_SAMPLE_S32BE = new AudioFormat( - Encoding.PCM_SIGNED, // encoding - AudioSystem.NOT_SPECIFIED, // sample rate - sampleSize, // sample size - channelSize, // channels - sampleSize / 8 * channelSize, // frame size - AudioSystem.NOT_SPECIFIED, // frame rate - true, // big endian? - properties); - - supportedFormats.add(PA_SAMPLE_S32BE); - } - - for (int channelSize : channelSizes) { - properties = new HashMap(); - properties.put(PULSEAUDIO_FORMAT_KEY, "PA_SAMPLE_S32LE"); - - int sampleSize = 32; - final AudioFormat PA_SAMPLE_S32LE = new AudioFormat( - Encoding.PCM_SIGNED, // encoding - AudioSystem.NOT_SPECIFIED, // sample rate - sampleSize, // sample size - channelSize, // channels - sampleSize / 8 * channelSize, // frame size - AudioSystem.NOT_SPECIFIED, // frame rate - false, // big endian? - properties); - - supportedFormats.add(PA_SAMPLE_S32LE); - } - - for (int channelSize : channelSizes) { - properties = new HashMap(); - properties.put(PULSEAUDIO_FORMAT_KEY, "PA_SAMPLE_U8"); - - int sampleSize = 8; // in bits - AudioFormat PA_SAMPLE_U8 = new AudioFormat(Encoding.PCM_UNSIGNED, // encoding - AudioSystem.NOT_SPECIFIED, // sample rate - sampleSize, // sample size - channelSize, // channels - sampleSize / 8 * channelSize, // frame size in bytes - AudioSystem.NOT_SPECIFIED, // frame rate - false, // big endian? - properties); - - supportedFormats.add(PA_SAMPLE_U8); - } - - return supportedFormats.toArray(new AudioFormat[0]); - } - - @Override - public Line getLine(Line.Info info) throws LineUnavailableException { - - if (!isLineSupported(info)) { - throw new IllegalArgumentException("Line unsupported: " + info); - } - - AudioFormat[] formats = null; - AudioFormat defaultFormat = null; - - if (DataLine.Info.class.isInstance(info)) { - ArrayList formatList = new ArrayList(); - AudioFormat[] requestedFormats = ((DataLine.Info) info) - .getFormats(); - for (int i = 0; i < requestedFormats.length; i++) { - AudioFormat f1 = requestedFormats[i]; - for (AudioFormat f2 : getSupportedFormats()) { - - if (f1.matches(f2)) { - formatList.add(f2); - defaultFormat = f1; - } - } - } - formats = formatList.toArray(new AudioFormat[0]); - - } else { - formats = getSupportedFormats(); - defaultFormat = new AudioFormat(Encoding.PCM_UNSIGNED, 44100, 8, 2, - 2, AudioSystem.NOT_SPECIFIED, false); - } - - if ((info.getLineClass() == SourceDataLine.class)) { - return new PulseAudioSourceDataLine(formats, defaultFormat); - } - - if ((info.getLineClass() == TargetDataLine.class)) { - /* check for permission to record audio */ - AudioPermission perm = new AudioPermission("record", null); - perm.checkGuard(null); - - return new PulseAudioTargetDataLine(formats, defaultFormat); - } - - if ((info.getLineClass() == Clip.class)) { - return new PulseAudioClip(formats, defaultFormat); - } - - if (Port.Info.class.isInstance(info)) { - Port.Info portInfo = (Port.Info) info; - if (portInfo.isSource()) { - /* check for permission to record audio */ - AudioPermission perm = new AudioPermission("record", null); - perm.checkGuard(null); - - return new PulseAudioSourcePort(portInfo.getName()); - } else { - return new PulseAudioTargetPort(portInfo.getName()); - } - } - - Debug.println(DebugLevel.Info, "PulseAudioMixer.getLine(): " - + "No matching line supported by PulseAudio"); - - throw new IllegalArgumentException("No matching lines found"); - - } - - @Override - public int getMaxLines(Line.Info info) { - /* - * PulseAudio supports (theoretically) unlimited number of streams for - * supported formats - */ - if (isLineSupported(info)) { - return AudioSystem.NOT_SPECIFIED; - } - - return 0; - } - - @Override - public Info getMixerInfo() { - return PulseAudioMixerInfo.getInfo(); - } - - public Line.Info[] getSourceLineInfo() { - return sourceLineInfos.toArray(new Line.Info[0]); - } - - @Override - public Line.Info[] getSourceLineInfo(Line.Info info) { - ArrayList infos = new ArrayList(); - - for (Line.Info supportedInfo : sourceLineInfos) { - if (info.matches(supportedInfo)) { - infos.add(supportedInfo); - } - } - return infos.toArray(new Line.Info[0]); - } - - @Override - public Line[] getSourceLines() { - return sourceLines.toArray(new Line[0]); - - } - - @Override - public Line.Info[] getTargetLineInfo() { - return targetLineInfos.toArray(new Line.Info[0]); - } - - @Override - public Line.Info[] getTargetLineInfo(Line.Info info) { - ArrayList infos = new ArrayList(); - - for (Line.Info supportedInfo : targetLineInfos) { - if (info.matches(supportedInfo)) { - infos.add(supportedInfo); - } - } - return infos.toArray(new Line.Info[0]); - } - - @Override - public Line[] getTargetLines() { - - /* check for permission to record audio */ - AudioPermission perm = new AudioPermission("record", null); - perm.checkGuard(null); - - return (Line[]) targetLines.toArray(new Line[0]); - } - - @Override - public boolean isLineSupported(Line.Info info) { - if (info != null) { - for (Line.Info myInfo : sourceLineInfos) { - if (info.matches(myInfo)) { - return true; - } - } - - for (Line.Info myInfo : targetLineInfos) { - if (info.matches(myInfo)) { - return true; - } - } - - } - return false; - - } - - @Override - public boolean isSynchronizationSupported(Line[] lines, boolean maintainSync) { - - return false; - } - - @Override - public void synchronize(Line[] lines, boolean maintainSync) { - - throw new IllegalArgumentException( - "Mixer does not support synchronizing lines"); - - // Line masterStream = null; - // for (Line line : lines) { - // if (line.isOpen()) { - // masterStream = line; - // break; - // } - // } - // if (masterStream == null) { - // // for now, can't synchronize lines if none of them is open (no - // // stream pointer to pass) - // // will see what to do about this later - // throw new IllegalArgumentException(); - // } - // - // try { - // - // for (Line line : lines) { - // if (line != masterStream) { - // - // ((PulseAudioDataLine) line) - // .reconnectforSynchronization(((PulseAudioDataLine) masterStream) - // .getStream()); - // - // } - // } - // } catch (LineUnavailableException e) { - // // we couldn't reconnect, so tell the user we failed by throwing an - // // exception - // throw new IllegalArgumentException(e); - // } - - } - - @Override - public void unsynchronize(Line[] lines) { - // FIXME should be able to implement this - throw new IllegalArgumentException(); - } - - @Override - public void addLineListener(LineListener listener) { - lineListeners.add(listener); - } - - @Override - synchronized public void close() { - - /* - * only allow the mixer to be controlled if either playback or recording - * is allowed - */ - - if (!this.isOpen) { - throw new IllegalStateException("Mixer is not open; cant close"); - } - - List linesToClose = new LinkedList(); - linesToClose.addAll(sourceLines); - if (sourceLines.size() > 0) { - - Debug.println(DebugLevel.Warning, "PulseAudioMixer.close(): " - + linesToClose.size() - + " source lines were not closed. closing them now."); - - linesToClose.addAll(sourceLines); - for (Line line : linesToClose) { - if (line.isOpen()) { - line.close(); - } - } - } - linesToClose.clear(); - - if (targetLines.size() > 0) { - Debug.println(DebugLevel.Warning, "PulseAudioMixer.close(): " - + linesToClose.size() - + " target lines have not been closed"); - - linesToClose.addAll(targetLines); - for (Line line : linesToClose) { - if (line.isOpen()) { - line.close(); - } - } - } - - synchronized (lineListeners) { - lineListeners.clear(); - } - - eventLoopThread.interrupt(); - - try { - eventLoopThread.join(); - } catch (InterruptedException e) { - System.out.println(this.getClass().getName() - + ": interrupted while waiting for eventloop to finish"); - } - - isOpen = false; - - refreshSourceAndTargetLines(); - - Debug.println(DebugLevel.Verbose, "PulseAudioMixer.close(): " - + "Mixer closed"); - - } - - @Override - public Control getControl(Type control) { - // mixer supports no controls - throw new IllegalArgumentException(); - } - - @Override - public Control[] getControls() { - // mixer supports no controls; return an array of length 0 - return new Control[] {}; - } - - @Override - public javax.sound.sampled.Line.Info getLineInfo() { - // System.out.println("DEBUG: PulseAudioMixer.getLineInfo() called"); - return new Line.Info(PulseAudioMixer.class); - } - - @Override - public boolean isControlSupported(Type control) { - // mixer supports no controls - return false; - } - - @Override - public boolean isOpen() { - return isOpen; - } - - @Override - public void open() throws LineUnavailableException { - openLocal(); - - } - - public void openLocal() throws LineUnavailableException { - openLocal(DEFAULT_APP_NAME); - } - - public void openLocal(String appName) throws LineUnavailableException { - openImpl(appName, null); - } - - public void openRemote(String appName, String host) - throws UnknownHostException, LineUnavailableException { - if (host == null) { - throw new NullPointerException("hostname"); - } - - final int PULSEAUDIO_DEFAULT_PORT = 4713; - - /* - * If trying to connect to a remote machine, check for permissions - */ - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkConnect(host,PULSEAUDIO_DEFAULT_PORT ); - } - - openImpl(appName, host); - } - - public void openRemote(String appName, String host, int port) - throws UnknownHostException, LineUnavailableException { - - if ((port < 1) && (port != -1)) { - throw new IllegalArgumentException("Invalid value for port"); - } - - if (host == null) { - throw new NullPointerException("hostname"); - } - - /* - * If trying to connect to a remote machine, check for permissions - */ - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkConnect(host, port); - } - - InetAddress addr = InetAddress.getAllByName(host)[0]; - - host = addr.getHostAddress(); - host = host + ":" + String.valueOf(port); - - openImpl(appName, host); - - } - - /* - * - * @param appName name of the application - * - * @param hostAndIp a string consisting of the host and ip address of the - * server to connect to. Format: ":". Set to null to indicate a - * local connection - */ - synchronized private void openImpl(String appName, String hostAndIp) - throws LineUnavailableException { - - if (isOpen) { - throw new IllegalStateException("Mixer is already open"); - } - - EventLoop eventLoop; - eventLoop = EventLoop.getEventLoop(); - eventLoop.setAppName(appName); - eventLoop.setServer(hostAndIp); - - ContextListener generalEventListener = new ContextListener() { - @Override - public void update(ContextEvent e) { - if (e.getType() == ContextEvent.READY) { - fireEvent(new LineEvent(PulseAudioMixer.this, - LineEvent.Type.OPEN, AudioSystem.NOT_SPECIFIED)); - } else if (e.getType() == ContextEvent.FAILED - || e.getType() == ContextEvent.TERMINATED) { - fireEvent(new LineEvent(PulseAudioMixer.this, - LineEvent.Type.CLOSE, AudioSystem.NOT_SPECIFIED)); - } - } - }; - - eventLoop.addContextListener(generalEventListener); - - final Semaphore ready = new Semaphore(0); - - ContextListener initListener = new ContextListener() { - - @Override - public void update(ContextEvent e) { - if (e.getType() == ContextEvent.READY - || e.getType() == ContextEvent.FAILED - || e.getType() == ContextEvent.TERMINATED) { - ready.release(); - } - } - - }; - - eventLoop.addContextListener(initListener); - - eventLoopThread = new Thread(eventLoop, "PulseAudio Eventloop Thread"); - - /* - * Make the thread exit if by some weird error it is the only thread - * running. The application should be able to exit if the main thread - * doesn't or can't (perhaps an assert?) do a mixer.close(). - */ - eventLoopThread.setDaemon(true); - eventLoopThread.start(); - - try { - // System.out.println("waiting..."); - ready.acquire(); - if (eventLoop.getStatus() != ContextEvent.READY) { - /* - * when exiting, wait for the thread to end otherwise we get one - * thread that inits the singleton with new data and the old - * thread then cleans up the singleton asserts fail all over the - * place - */ - eventLoop.removeContextListener(initListener); - eventLoopThread.interrupt(); - eventLoopThread.join(); - throw new LineUnavailableException(); - } - eventLoop.removeContextListener(initListener); - // System.out.println("got signal"); - } catch (InterruptedException e) { - System.out.println("PulseAudioMixer: got interrupted while waiting for the EventLoop to initialize"); - } - - // System.out.println(this.getClass().getName() + ": ready"); - - this.isOpen = true; - - // sourceLineInfo and targetLineInfo need to be updated with - // port infos, which can only be obtained after EventLoop had started - - refreshSourceAndTargetLines(); - - for (String portName : eventLoop.updateSourcePortNameList()) { - sourceLineInfos.add(new Port.Info(Port.class, portName, true)); - } - - for (String portName : eventLoop.updateTargetPortNameList()) { - targetLineInfos.add(new Port.Info(Port.class, portName, false)); - } - - Debug.println(DebugLevel.Debug, "PulseAudioMixer.open(): " - + "Mixer opened"); - - } - - @Override - public void removeLineListener(LineListener listener) { - lineListeners.remove(listener); - } - - /* - * Should this method be synchronized? I had a few reasons, but i forgot - * them Pros: - Thread safety? - * - * Cons: - eventListeners are run from other threads, if those then call - * fireEvent while a method is waiting on a listener, this synchronized - * block wont be entered: deadlock! - */ - private void fireEvent(final LineEvent e) { - synchronized (lineListeners) { - for (LineListener lineListener : lineListeners) { - lineListener.update(e); - } - } - } - - void addSourceLine(PulseAudioLine line) { - sourceLines.add(line); - } - - void removeSourceLine(PulseAudioLine line) { - sourceLines.remove(line); - } - - void addTargetLine(PulseAudioLine line) { - targetLines.add(line); - } - - void removeTargetLine(PulseAudioLine line) { - targetLines.remove(line); - } - - void refreshSourceAndTargetLines() { - - sourceLineInfos.clear(); - targetLineInfos.clear(); - - sourceLineInfos.addAll(staticSourceLineInfos); - - targetLineInfos.addAll(staticTargetLineInfos); - - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerInfo.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerInfo.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* PulseAudioMixerInfo.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import javax.sound.sampled.Mixer; - -public final class PulseAudioMixerInfo extends Mixer.Info { - // singleton - - private static PulseAudioMixerInfo _instance = null; - - protected PulseAudioMixerInfo(String name, String vendor, - String description, String version) { - super(name, vendor, description, version); - } - - // the "getInstance()" method - synchronized public static PulseAudioMixerInfo getInfo() { - if (_instance == null) { - _instance = new PulseAudioMixerInfo("PulseAudio Mixer", "IcedTea", - "the ear-candy mixer", "0.02"); - } - - return _instance; - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerProvider.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerProvider.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* PulseAudioMixerProvider.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import javax.sound.sampled.Mixer; -import javax.sound.sampled.Mixer.Info; - -public class PulseAudioMixerProvider extends - javax.sound.sampled.spi.MixerProvider { - - @Override - public Mixer getMixer(Info info) { - // System.out.println("DEBUG: getMixer called"); - if (info.equals(PulseAudioMixerInfo.getInfo())) { - return PulseAudioMixer.getInstance(); - } else { - throw new IllegalArgumentException("Mixer type not supported"); - } - } - - @Override - public Info[] getMixerInfo() { - // System.out.println("DEBUG: get mixer info called"); - Mixer.Info[] m = { PulseAudioMixerInfo.getInfo() }; - return m; - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPlaybackLine.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPlaybackLine.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* PulseAudioClip.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -/** - * Represents a Line that supports changing the volume - */ -interface PulseAudioPlaybackLine { - - static final int SECONDS_TO_MICROSECONDS = 1000000; - - /** - * Set the volume of the Line (ie, sink input, source, or sink) - * - * @return an Operation object which can be used to check if the operation - * has completed - */ - byte[] native_set_volume(float value); - - /** - * - * Update the volume information of a Line (sink input, source or sink) - * - * @return an Operation object which can be used to check if the operation - * has been completed - */ - byte[] native_update_volume(); - - - /** - * Gets the cached volume. To get the current volume, call - * native_update_volume, and then call this method to get the updated - * volume. - * - * @return the cached volume of the Line - */ - float getCachedVolume(); - - /** - * Set the cached value of a line - * - */ - void setCachedVolume(float volume); - - /** - * Check if a line is open - * - * @return true if line is open - */ - boolean isOpen(); - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPort.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPort.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +0,0 @@ -/* PulseAudioClip.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.Port; - -abstract class PulseAudioPort extends PulseAudioLine implements Port, - PulseAudioPlaybackLine { - - private String name; - - /* - * Variable used in native code - */ - @SuppressWarnings("unused") - private byte[] contextPointer; - @SuppressWarnings("unused") - private int channels; - - private EventLoop eventLoop; - - private float cachedVolume; - - private PulseAudioVolumeControl volumeControl; - - static { - SecurityWrapper.loadNativeLibrary(); - } - - PulseAudioPort(String portName) { - this.name = portName; - this.eventLoop = EventLoop.getEventLoop(); - this.contextPointer = eventLoop.getContextPointer(); - - updateVolumeInfo(); - - volumeControl = new PulseAudioVolumeControl(this, eventLoop); - controls.add(volumeControl); - - /* - * unlike other lines, Ports must either be open or close - * - * close = no sound. open = sound - */ - open(); - - // System.out.println("Opened Target Port " + name); - } - - // FIXME why public - @Override - public abstract byte[] native_set_volume(float newValue); - - /** - * - * @see {@link update_channels_and_volume} - */ - // FIXME why public - public abstract byte[] native_update_volume(); - - @Override - public float getCachedVolume() { - return this.cachedVolume; - } - - @Override - public void setCachedVolume(float value) { - this.cachedVolume = value; - - } - - private void updateVolumeInfo() { - Operation op; - synchronized (eventLoop.threadLock) { - op = new Operation(native_update_volume()); - } - - op.waitForCompletion(); - op.releaseReference(); - } - - /** - * Callback used by JNI when native_update_volume completes - * - * @param channels - * the number of channels - * @param cachedVolume - * the new volume - */ - @SuppressWarnings("unused") - void update_channels_and_volume(int channels, float volume) { - this.channels = channels; - this.cachedVolume = volume; - } - - @Override - public void close() { - - native_set_volume((float) 0); - isOpen = false; - fireLineEvent(new LineEvent(this, LineEvent.Type.CLOSE, - AudioSystem.NOT_SPECIFIED)); - } - - @Override - public abstract Line.Info getLineInfo(); - - @Override - public void open() { - if (isOpen) { - return; - } - native_set_volume(cachedVolume); - isOpen = true; - fireLineEvent(new LineEvent(this, LineEvent.Type.OPEN, - AudioSystem.NOT_SPECIFIED)); - } - - public String getName() { - return this.name; - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,347 +0,0 @@ -/* PulseAudioSourceDataLine.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.util.ArrayList; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.SourceDataLine; - -import org.classpath.icedtea.pulseaudio.Debug.DebugLevel; - -public final class PulseAudioSourceDataLine extends PulseAudioDataLine - implements SourceDataLine, PulseAudioPlaybackLine { - - private PulseAudioVolumeControl volumeControl; - - public static final String DEFAULT_SOURCEDATALINE_NAME = "Audio Stream"; - - /* - * Package-private constructor only called by PulseAudioMixer - */ - PulseAudioSourceDataLine(AudioFormat[] formats, AudioFormat defaultFormat) { - - this.supportedFormats = formats; - this.lineListeners = new ArrayList(); - this.defaultFormat = defaultFormat; - this.currentFormat = defaultFormat; - this.streamName = DEFAULT_SOURCEDATALINE_NAME; - - } - - @Override - synchronized public void open(AudioFormat format, int bufferSize) - throws LineUnavailableException { - - super.open(format, bufferSize); - - volumeControl = new PulseAudioVolumeControl(this, eventLoop); - controls.add(volumeControl); - - PulseAudioMixer parentMixer = PulseAudioMixer.getInstance(); - parentMixer.addSourceLine(this); - - Debug.println(DebugLevel.Verbose, "PulseAudioSourceDataLine.open(): " - + "line opened"); - - } - - @Override - public void open(AudioFormat format) throws LineUnavailableException { - open(format, DEFAULT_BUFFER_SIZE); - } - - // FIXME - public byte[] native_set_volume(float value) { - synchronized (eventLoop.threadLock) { - return stream.native_set_volume(value); - } - } - - public byte[] native_update_volume() { - synchronized (eventLoop.threadLock) { - return stream.native_update_volume(); - } - } - - @Override - public float getCachedVolume() { - return stream.getCachedVolume(); - } - - @Override - synchronized public void setCachedVolume(float value) { - stream.setCachedVolume(value); - } - - @Override - protected void connectLine(int bufferSize, Stream masterStream) - throws LineUnavailableException { - StreamBufferAttributes bufferAttributes = - new StreamBufferAttributes( - bufferSize, - bufferSize / 4, - bufferSize / 8, - Math.max(bufferSize / 10, 100), - 0); - - if (masterStream != null) { - synchronized (eventLoop.threadLock) { - stream.connectForPlayback(Stream.DEFAULT_DEVICE, - bufferAttributes, masterStream.getStreamPointer()); - } - } else { - synchronized (eventLoop.threadLock) { - stream.connectForPlayback(Stream.DEFAULT_DEVICE, - bufferAttributes, null); - } - } - } - - @Override - public int write(byte[] data, int offset, int length) { - // can't call write() without open()ing first, but can call write() - // without start()ing - synchronized (this) { - writeInterrupted = false; - } - - if (!isOpen()) { - // A closed line can write exactly 0 bytes. - return 0; - } - - int frameSize = currentFormat.getFrameSize(); - if (length % frameSize != 0) { - throw new IllegalArgumentException( - "amount of data to write does not represent an integral number of frames"); - } - - if (length < 0) { - throw new IllegalArgumentException("length is negative"); - } - - if (length < 0 || offset < 0 || offset > data.length - length) { - throw new ArrayIndexOutOfBoundsException( - "Overflow condition: buffer.length=" + data.length + - " offset= " + offset + " length=" + length ); - } - - int position = offset; - int remainingLength = length; - int availableSize = 0; - - int sizeWritten = 0; - - boolean interrupted = false; - - while (remainingLength != 0) { - - synchronized (eventLoop.threadLock) { - - do { - synchronized (this) { - if (writeInterrupted) { - return sizeWritten; - } - } - - if (availableSize == -1) { - return sizeWritten; - } - availableSize = stream.getWritableSize(); - - if (availableSize == 0) { - try { - eventLoop.threadLock.wait(100); - } catch (InterruptedException e) { - // ignore for now - interrupted = true; - } - - } - - } while (availableSize == 0); - - if (availableSize > remainingLength) { - availableSize = remainingLength; - } - - // only write entire frames, so round down avialableSize to - // a multiple of frameSize - availableSize = (availableSize / frameSize) * frameSize; - - synchronized (this) { - if (writeInterrupted) { - return sizeWritten; - } - /* write a little bit of the buffer */ - stream.write(data, position, availableSize); - } - - sizeWritten += availableSize; - position += availableSize; - remainingLength -= availableSize; - - framesSinceOpen += availableSize / frameSize; - - } - } - - // all the data should have been played by now - assert (sizeWritten == length); - - if (interrupted) { - Thread.currentThread().interrupt(); - } - - return sizeWritten; - } - - @Override - public int available() { - synchronized (eventLoop.threadLock) { - return stream.getWritableSize(); - } - }; - - @Override - public int getFramePosition() { - return (int) framesSinceOpen; - } - - @Override - public long getLongFramePosition() { - return framesSinceOpen; - } - - @Override - public long getMicrosecondPosition() { - - float frameRate = currentFormat.getFrameRate(); - float time = framesSinceOpen / frameRate; // seconds - long microseconds = (long) (time * SECONDS_TO_MICROSECONDS); - return microseconds; - } - - @Override - public void drain() { - - synchronized (this) { - writeInterrupted = true; - } - - do { - synchronized (this) { - if (!isOpen()) { - return; - } - if (getBytesInBuffer() == 0) { - return; - } - if (isStarted) { - break; - } - try { - this.wait(100); - } catch (InterruptedException e) { - return; - } - } - } while (!isStarted); - - Operation operation; - - synchronized (eventLoop.threadLock) { - operation = stream.drain(); - } - - operation.waitForCompletion(); - operation.releaseReference(); - - } - - @Override - public void flush() { - synchronized (this) { - writeInterrupted = true; - } - - if (isOpen()) { - Operation operation; - synchronized (eventLoop.threadLock) { - operation = stream.flush(); - } - - operation.waitForCompletion(); - operation.releaseReference(); - } - - } - - @Override - synchronized public void close() { - - if (!isOpen()) { - return; - } - - writeInterrupted = true; - - PulseAudioMixer parent = PulseAudioMixer.getInstance(); - parent.removeSourceLine(this); - - super.close(); - - Debug.println(DebugLevel.Verbose, "PulseAudioSourceDataLine.close():" - + " line closed"); - - } - - @Override - public Line.Info getLineInfo() { - return new DataLine.Info(SourceDataLine.class, supportedFormats, - StreamBufferAttributes.MIN_VALUE, - StreamBufferAttributes.MAX_VALUE); - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourcePort.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourcePort.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* PulseAudioClip.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import javax.sound.sampled.AudioPermission; -import javax.sound.sampled.Line; -import javax.sound.sampled.Port; - -final class PulseAudioSourcePort extends PulseAudioPort { - - /* aka mic */ - - static { - SecurityWrapper.loadNativeLibrary(); - } - - PulseAudioSourcePort(String name) { - super(name); - } - - public void open() { - - /* check for permission to record audio */ - AudioPermission perm = new AudioPermission("record", null); - perm.checkGuard(null); - - super.open(); - - PulseAudioMixer parent = PulseAudioMixer.getInstance(); - parent.addSourceLine(this); - } - - public void close() { - - /* check for permission to record audio */ - AudioPermission perm = new AudioPermission("record", null); - perm.checkGuard(null); - - if (!isOpen) { - throw new IllegalStateException("Port is not open; so cant close"); - } - - PulseAudioMixer parent = PulseAudioMixer.getInstance(); - parent.removeSourceLine(this); - - super.close(); - } - - // FIXME - public native byte[] native_set_volume(float newValue); - - // FIXME - public native byte[] native_update_volume(); - - @Override - public Line.Info getLineInfo() { - return new Port.Info(Port.class, getName(), false); - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,421 +0,0 @@ -/* PulseAudioTargetDataLine.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioPermission; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.TargetDataLine; - -import org.classpath.icedtea.pulseaudio.Debug.DebugLevel; - -public final class PulseAudioTargetDataLine extends PulseAudioDataLine - implements TargetDataLine { - - /* - * This contains the data from the PulseAudio buffer that has since been - * dropped. If 20 bytes of a fragment of size 200 are read, the other 180 - * are dumped in this - */ - private byte[] fragmentBuffer; - - /* - * these are set to true only by the respective functions (flush(), drain()) - * set to false only by read() - */ - private boolean flushed = false; - private boolean drained = false; - - public static final String DEFAULT_TARGETDATALINE_NAME = "Audio Stream"; - - PulseAudioTargetDataLine(AudioFormat[] formats, AudioFormat defaultFormat) { - this.supportedFormats = formats; - this.defaultFormat = defaultFormat; - this.currentFormat = defaultFormat; - this.streamName = DEFAULT_TARGETDATALINE_NAME; - - } - - @Override - synchronized public void close() { - if (!isOpen()) { - // Probably due to some programmer error, we are being - // asked to close an already closed line. Oh well. - Debug.println(DebugLevel.Verbose, - "PulseAudioTargetDataLine.close(): " - + "Line closed that wasn't open."); - return; - } - - /* check for permission to record audio */ - AudioPermission perm = new AudioPermission("record", null); - perm.checkGuard(null); - - PulseAudioMixer parentMixer = PulseAudioMixer.getInstance(); - parentMixer.removeTargetLine(this); - - super.close(); - - Debug.println(DebugLevel.Verbose, "PulseAudioTargetDataLine.close(): " - + "Line closed"); - } - - @Override - synchronized public void open(AudioFormat format, int bufferSize) - throws LineUnavailableException { - /* check for permission to record audio */ - AudioPermission perm = new AudioPermission("record", null); - perm.checkGuard(null); - - if (isOpen()) { - throw new IllegalStateException("already open"); - } - super.open(format, bufferSize); - - /* initialize all the member variables */ - framesSinceOpen = 0; - fragmentBuffer = null; - flushed = false; - drained = false; - - /* add this open line to the mixer */ - PulseAudioMixer parentMixer = PulseAudioMixer.getInstance(); - parentMixer.addTargetLine(this); - - Debug.println(DebugLevel.Verbose, "PulseAudioTargetDataLine.open(): " - + "Line opened"); - } - - @Override - synchronized public void open(AudioFormat format) - throws LineUnavailableException { - open(format, DEFAULT_BUFFER_SIZE); - } - - @Override - protected void connectLine(int bufferSize, Stream masterStream) - throws LineUnavailableException { - int fs = currentFormat.getFrameSize(); - float fr = currentFormat.getFrameRate(); - int bps = (int)(fs*fr); // bytes per second. - - // if 2 seconds' worth of data can fit in the buffer of the specified - // size, we don't have to adjust the latency. Otherwise we do, so as - // to avoid overruns. - long flags = Stream.FLAG_START_CORKED; - StreamBufferAttributes bufferAttributes; - if (bps*2 < bufferSize) { - // pulse audio completely ignores our fragmentSize attribute unless - // ADJUST_LATENCY is set, so we just leave it at -1. - bufferAttributes = new StreamBufferAttributes(bufferSize, -1, -1, -1, -1); - } else { - flags |= Stream.FLAG_ADJUST_LATENCY; - // in this case, the pulse audio docs: - // http://www.pulseaudio.org/wiki/LatencyControl - // say every field (including bufferSize) must be initialized - // to -1 except fragmentSize. - // XXX: but in my tests, it just sets it to about 4MB, which - // effectively makes it impossible to allocate a small buffer - // and nothing bad happens (yet) when you don't set it to -1 - // so we just leave it at bufferSize. - // XXX: the java api has no way to specify latency, which probably - // means it should be as low as possible. Right now this method's - // primary concern is avoiding dropouts, and if the user-provided - // buffer size is large enough, we leave the latency up to pulse - // audio (which sets it to something extremely high - about 2 - // seconds). We might want to always set a low latency. - int fragmentSize = bufferSize/2; - fragmentSize = Math.max((fragmentSize/fs)*fs, fs); - bufferAttributes = new StreamBufferAttributes(bufferSize, -1, -1, -1, fragmentSize); - } - - synchronized (eventLoop.threadLock) { - stream.connectForRecording(Stream.DEFAULT_DEVICE, flags, bufferAttributes); - } - } - - @Override - public int read(byte[] data, int offset, int length) { - - /* check state and inputs */ - - if (!isOpen()) { - // A closed line can produce zero bytes of data. - return 0; - } - - int frameSize = currentFormat.getFrameSize(); - - if (length % frameSize != 0) { - throw new IllegalArgumentException( - "amount of data to read does not represent an integral number of frames"); - } - - if (length < 0) { - throw new IllegalArgumentException("length is negative"); - } - - if ( offset < 0 || offset > data.length - length) { - throw new ArrayIndexOutOfBoundsException("array size: " + data.length - + " offset:" + offset + " length:" + length ); - } - - /* everything ok */ - - int position = offset; - int remainingLength = length; - int sizeRead = 0; - - /* bytes read on each iteration of loop */ - int bytesRead; - - flushed = false; - drained = false; - - /* - * to read, we first take stuff from the fragmentBuffer - */ - - /* on first read() of the line, fragmentBuffer is null */ - synchronized (this) { - if (fragmentBuffer != null) { - boolean fragmentBufferSmaller = fragmentBuffer.length < length; - int smallerBufferLength = Math.min(fragmentBuffer.length, - length); - System.arraycopy(fragmentBuffer, 0, data, position, - smallerBufferLength); - framesSinceOpen += smallerBufferLength - / currentFormat.getFrameSize(); - - if (!fragmentBufferSmaller) { - /* - * if fragment was larger, then we already have all the data - * we need. clean up the buffer before returning. Make a new - * fragmentBuffer from the remaining bytes - */ - int remainingBytesInFragment = (fragmentBuffer.length - length); - byte[] newFragmentBuffer = new byte[remainingBytesInFragment]; - System.arraycopy(fragmentBuffer, length, newFragmentBuffer, - 0, newFragmentBuffer.length); - fragmentBuffer = newFragmentBuffer; - return length; - } - - /* done with fragment buffer, remove it */ - bytesRead = smallerBufferLength; - sizeRead += bytesRead; - position += bytesRead; - remainingLength -= bytesRead; - fragmentBuffer = null; - } - } - - /* - * if we need to read more data, then we read from PulseAudio's buffer - */ - while (remainingLength != 0) { - synchronized (this) { - - if (!isOpen() || !isStarted) { - return sizeRead; - } - - if (flushed) { - flushed = false; - return sizeRead; - } - - if (drained) { - drained = false; - return sizeRead; - } - - byte[] currentFragment; - synchronized (eventLoop.threadLock) { - - /* read a fragment, and drop it from the server */ - currentFragment = stream.peek(); - - stream.drop(); - if (currentFragment == null) { - Debug.println(DebugLevel.Verbose, - "PulseAudioTargetDataLine.read(): " - + " error in stream.peek()"); - continue; - } - - bytesRead = Math.min(currentFragment.length, - remainingLength); - - /* - * we read more than we required, save the rest of the data - * in the fragmentBuffer - */ - if (bytesRead < currentFragment.length) { - /* allocate a buffer to store unsaved data */ - fragmentBuffer = new byte[currentFragment.length - - bytesRead]; - - /* copy over the unsaved data */ - System.arraycopy(currentFragment, bytesRead, - fragmentBuffer, 0, currentFragment.length - - bytesRead); - } - - System.arraycopy(currentFragment, 0, data, position, - bytesRead); - - sizeRead += bytesRead; - position += bytesRead; - remainingLength -= bytesRead; - framesSinceOpen += bytesRead / currentFormat.getFrameSize(); - } - } - } - - // all the data should have been played by now - assert (sizeRead == length); - - return sizeRead; - - } - - @Override - public void drain() { - - // blocks when there is data on the line - // http://www.jsresources.org/faq_audio.html#stop_drain_tdl - while (true) { - synchronized (this) { - if (!isStarted || !isOpen()) { - break; - } - } - try { - //TODO: Is this the best length of sleep? - //Maybe in case this loop runs for a long time - //it would be good to switch to a longer - //sleep. Like bump it up each iteration after - //the Nth iteration, up to a MAXSLEEP length. - Thread.sleep(100); - } catch (InterruptedException e) { - // do nothing - } - } - - synchronized (this) { - drained = true; - } - } - - @Override - public synchronized void flush() { - if (isOpen()) { - - /* flush the buffer on pulseaudio's side */ - Operation operation; - synchronized (eventLoop.threadLock) { - operation = stream.flush(); - } - operation.waitForCompletion(); - operation.releaseReference(); - } - - flushed = true; - /* flush the partial fragment we stored */ - fragmentBuffer = null; - } - - @Override - public int available() { - if (!isOpen()) { - // a closed line has 0 bytes available. - return 0; - } - - synchronized (eventLoop.threadLock) { - return stream.getReableSize(); - } - } - - @Override - public int getFramePosition() { - return (int) framesSinceOpen; - } - - @Override - public long getLongFramePosition() { - return framesSinceOpen; - } - - @Override - public long getMicrosecondPosition() { - return (long) (framesSinceOpen / currentFormat.getFrameRate()); - } - - /* - * A TargetData starts when we ask it to and continues playing until we ask - * it to stop. There are no buffer underruns/overflows or anything so we - * will just fire the LineEvents manually - */ - - @Override - synchronized public void start() { - super.start(); - - fireLineEvent(new LineEvent(this, LineEvent.Type.START, framesSinceOpen)); - } - - @Override - synchronized public void stop() { - super.stop(); - - fireLineEvent(new LineEvent(this, LineEvent.Type.STOP, framesSinceOpen)); - } - - @Override - public Line.Info getLineInfo() { - return new DataLine.Info(TargetDataLine.class, supportedFormats, - StreamBufferAttributes.MIN_VALUE, - StreamBufferAttributes.MAX_VALUE); - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetPort.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetPort.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* PulseAudioClip.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import javax.sound.sampled.Line; -import javax.sound.sampled.Port; - -final class PulseAudioTargetPort extends PulseAudioPort { - - /* aka speaker */ - - static { - SecurityWrapper.loadNativeLibrary(); - } - - PulseAudioTargetPort(String name) { - super(name); - } - - @Override - public void open() { - - super.open(); - - PulseAudioMixer parent = PulseAudioMixer.getInstance(); - parent.addTargetLine(this); - } - - @Override - public void close() { - - if (!isOpen) { - throw new IllegalStateException("not open, so cant close Port"); - } - - PulseAudioMixer parent = PulseAudioMixer.getInstance(); - parent.removeTargetLine(this); - - super.close(); - } - - // FIXME - public native byte[] native_set_volume(float newValue); - - // FIXME - public native byte[] native_update_volume(); - - @Override - public Line.Info getLineInfo() { - return new Port.Info(Port.class, getName(), false); - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioVolumeControl.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioVolumeControl.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* PulseAudioVolumeControl.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import javax.sound.sampled.FloatControl; - -final class PulseAudioVolumeControl extends FloatControl { - - static final int MAX_VOLUME = 65536; - static final int MIN_VOLUME = 0; - - protected PulseAudioVolumeControl(PulseAudioPlaybackLine line, - EventLoop eventLoop) { - - /* - * the initial volume is ignored by pulseaudio. - */ - super(FloatControl.Type.VOLUME, MIN_VOLUME, MAX_VOLUME, 1, -1, line - .getCachedVolume(), "pulseaudio units", "Volume Off", - "Default Volume", "Full Volume"); - this.line = line; - this.eventLoop = eventLoop; - } - - private EventLoop eventLoop; - private PulseAudioPlaybackLine line; - - @Override - public synchronized void setValue(float newValue) { - if (newValue > MAX_VOLUME || newValue < MIN_VOLUME) { - throw new IllegalArgumentException("invalid value"); - } - - if (!line.isOpen()) { - return; - } - - setStreamVolume(newValue); - - line.setCachedVolume(newValue); - } - - protected synchronized void setStreamVolume(float newValue) { - Operation op; - synchronized (eventLoop.threadLock) { - op = new Operation(line.native_set_volume(newValue)); - } - - op.waitForCompletion(); - op.releaseReference(); - - } - - public synchronized float getValue() { - Operation op; - synchronized (eventLoop.threadLock) { - op = new Operation(line.native_update_volume()); - } - - op.waitForCompletion(); - op.releaseReference(); - - return line.getCachedVolume(); - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/SecurityWrapper.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/SecurityWrapper.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -package org.classpath.icedtea.pulseaudio; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -/** - * A wrapper around the security sensitive functions - * - */ -final class SecurityWrapper { - - static void loadNativeLibrary() { - - if (System.getSecurityManager() != null) { - PrivilegedAction action = new PrivilegedAction() { - @Override - public Boolean run() { - System.loadLibrary("pulse-java"); - return true; - } - - }; - - AccessController.doPrivileged(action); - - } else { - System.loadLibrary("pulse-java"); - } - - } -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Stream.java --- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Stream.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,869 +0,0 @@ -/* PulseAudioClip.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import javax.sound.sampled.LineUnavailableException; - -/** - * - * This class encapsulates a pa_stream object and provides easier access to the - * native functions - * - * - * for more details on this see the pa_stream_* functions in the pulseaudio api - * docs - * - */ -final class Stream { - - public interface StateListener { - public void update(); - } - - public interface CorkListener { - public void update(); - } - - public interface WriteListener { - public void update(); - } - - public interface ReadListener { - public void update(); - } - - public interface OverflowListener { - public void update(); - } - - public interface UnderflowListener { - public void update(); - } - - public interface PlaybackStartedListener { - public void update(); - } - - public interface LatencyUpdateListener { - public void update(); - } - - public interface MovedListener { - public void update(); - } - - public interface UpdateTimingInfoListener { - public void update(); - } - - public interface SuspendedListener { - public void update(); - } - - // see comments in ContextEvent.java and Operation.java - // These are the possible stream states. - public static long STATE_UNCONNECTED = -1, - STATE_CREATING = -1, - STATE_READY = -1, - STATE_FAILED = -1, - STATE_TERMINATED = -1; - - // Throw an IllegalStateException if value is not one of the possible - // states. Otherwise return the input. - public static long checkNativeStreamState(long value) { - if (!Arrays.asList(STATE_UNCONNECTED, STATE_CREATING, - STATE_READY, STATE_FAILED, STATE_TERMINATED - ).contains(value)) { - throw new IllegalStateException("Illegal constant for ContextEvent: " + value); - } - return value; - } - - // These are stream flags. - public static long FLAG_NOFLAGS = -1, - FLAG_START_CORKED = -1, - FLAG_INTERPOLATE_TIMING = -1, - FLAG_NOT_MONOTONIC = -1, - FLAG_AUTO_TIMING_UPDATE = -1, - FLAG_NO_REMAP_CHANNELS = -1, - FLAG_NO_REMIX_CHANNELS = -1, - FLAG_FIX_FORMAT = -1, - FLAG_FIX_RATE = -1, - FLAG_FIX_CHANNELS = -1, - FLAG_DONT_MOVE = -1, - FLAG_VARIABLE_RATE = -1, - FLAG_PEAK_DETECT = -1, - FLAG_START_MUTED = -1, - FLAG_ADJUST_LATENCY = -1, - FLAG_EARLY_REQUESTS = -1, - FLAG_DONT_INHIBIT_AUTO_SUSPEND = -1, - FLAG_START_UNMUTED = -1, - FLAG_FAIL_ON_SUSPEND = -1; - - private static native void init_constants(); - - // We don't change this to static longs like we did with all other pulse - // audio enums mirrored in java because we never use the pulse audio - // integer value of formats on the java side. In java, the handling of - // formats is strictly symbolic and string based. For that, enums are - // better. - public static enum Format { - PA_SAMPLE_U8, - PA_SAMPLE_ULAW, - PA_SAMPLE_ALAW, - PA_SAMPLE_S16LE, - PA_SAMPLE_S16BE, - PA_SAMPLE_FLOAT32LE, - PA_SAMPLE_FLOAT32BE, - PA_SAMPLE_S32LE, - PA_SAMPLE_S32BE - } - - public static final String DEFAULT_DEVICE = null; - - // stores a pointer to pa_stream - private byte[] streamPointer; - // stores a pointer to the java_context/this object for callbacks - private byte[] contextPointer; - - static { - SecurityWrapper.loadNativeLibrary(); - init_constants(); - } - - private Format format; - private float cachedVolume; - - private StreamBufferAttributes bufAttr = new StreamBufferAttributes(0,0,0,0,0); - private static final Object bufAttrMutex = new Object(); - - private List stateListeners; - private List writeListeners; - private List readListeners; - private List overflowListeners; - private List underflowListeners; - private List playbackStartedListeners; - private List latencyUpdateListeners; - private List movedListeners; - private List suspendedListeners; - private List corkListeners; - - private native void native_pa_stream_new(byte[] contextPointer, - String name, String format, int sampleRate, int channels); - - private native void native_pa_stream_unref(); - - private native long native_pa_stream_get_state(); - - private native byte[] native_pa_stream_get_context(); - - private native int native_pa_stream_get_index(); - - private native int native_pa_stream_get_device_index(); - - private native String native_pa_stream_get_device_name(); - - private native int native_pa_stream_is_suspended(); - - private native int native_pa_stream_connect_playback(String name, - int bufferMaxLength, int bufferTargetLength, - int bufferPreBuffering, int bufferMinimumRequest, - int bufferFragmentSize, long flags, byte[] volumePointer, - byte[] sync_streamPointer); - - private native int native_pa_stream_connect_record(String name, - int bufferMaxLength, int bufferTargetLength, - int bufferPreBuffering, int bufferMinimumRequest, - int bufferFragmentSize, long flags, byte[] volumePointer, - byte[] sync_streamPointer); - - private native int native_pa_stream_disconnect(); - - private native int native_pa_stream_write(byte[] data, int offset, - int length); - - private native byte[] native_pa_stream_peek(); - - private native int native_pa_stream_drop(); - - private native int native_pa_stream_writable_size(); - - private native int native_pa_stream_readable_size(); - - private native byte[] native_pa_stream_drain(); - - private native byte[] native_pa_stream_updateTimingInfo(); - - public native int bytesInBuffer(); - - /* - * pa_operation pa_stream_update_timing_info (pa_streamp, - * pa_stream_success_cb_t cb, voiduserdata) Request a timing info structure - * update for a stream. - */ - - private native int native_pa_stream_is_corked(); - - private native byte[] native_pa_stream_cork(int b); - - private native byte[] native_pa_stream_flush(); - - /* - * pa_operation pa_stream_prebuf (pa_streams, pa_stream_success_cb_t cb, - * voiduserdata) Reenable prebuffering as specified in the pa_buffer_attr - * structure. - */ - - private native byte[] native_pa_stream_trigger(); - - /* returns an operationPointer */ - private native byte[] native_pa_stream_set_name(String name); - - /* Return the current playback/recording time */ - private native long native_pa_stream_get_time(); - - /* Return the total stream latency */ - private native long native_pa_stream_get_latency(); - - /* - * const pa_timing_info pa_stream_get_timing_info (pa_streams) Return the - * latest raw timing data structure. - */ - - private native StreamSampleSpecification native_pa_stream_get_sample_spec(); - - /* - * const pa_channel_map pa_stream_get_channel_map (pa_streams) Return a - * pointer to the stream's channel map. const - */ - private native StreamBufferAttributes native_pa_stream_get_buffer_attr(); - - private native byte[] native_pa_stream_set_buffer_attr( - StreamBufferAttributes info); - - private native byte[] native_pa_stream_update_sample_rate(int rate); - - native byte[] native_set_volume(float newValue); - - native byte[] native_update_volume(); - - /* - * pa_operation pa_stream_proplist_update (pa_streams, pa_update_mode_t - * mode, pa_proplistp, pa_stream_success_cb_t cb, voiduserdata) Update the - * property list of the sink input/source output of this stream, adding new - * entries. pa_operation pa_stream_proplist_remove (pa_streams, const char - * const keys[], pa_stream_success_cb_t cb, voiduserdata) Update the - * property list of the sink input/source output of this stream, remove - * entries. int pa_stream_set_monitor_stream (pa_streams, uint32_t - * sink_input_idx) For record streams connected to a monitor source: monitor - * only a very specific sink input of the sink. uint32_t - * pa_stream_get_monitor_stream (pa_streams) Return what has been set with - * pa_stream_set_monitor_stream() ebfore. - */ - - Stream(byte[] contextPointer, String name, Format format, int sampleRate, - int channels) { - // System.out.println("format: " + format.toString()); - - stateListeners = new LinkedList(); - writeListeners = new LinkedList(); - readListeners = new LinkedList(); - overflowListeners = new LinkedList(); - underflowListeners = new LinkedList(); - playbackStartedListeners = new LinkedList(); - latencyUpdateListeners = new LinkedList(); - movedListeners = new LinkedList(); - suspendedListeners = new LinkedList(); - corkListeners = new LinkedList(); - this.format = format; - - StreamSampleSpecification spec = new StreamSampleSpecification(format, - sampleRate, channels); - - native_pa_stream_new(contextPointer, name, spec.getFormat().toString(), - spec.getRate(), spec.getChannels()); - } - - void addStateListener(StateListener listener) { - synchronized (stateListeners) { - stateListeners.add(listener); - } - } - - void removeStateListener(StateListener listener) { - synchronized (stateListeners) { - stateListeners.remove(listener); - } - - } - - void addWriteListener(WriteListener listener) { - synchronized (writeListeners) { - writeListeners.add(listener); - } - } - - void removeWriteListener(WriteListener listener) { - synchronized (writeListeners) { - writeListeners.remove(listener); - } - } - - void addReadListener(ReadListener listener) { - synchronized (readListeners) { - readListeners.add(listener); - } - } - - void removeReadListener(ReadListener listener) { - synchronized (readListeners) { - readListeners.remove(listener); - } - } - - void addOverflowListener(OverflowListener listener) { - synchronized (overflowListeners) { - overflowListeners.add(listener); - } - } - - void removeOverflowListener(OverflowListener listener) { - synchronized (overflowListeners) { - overflowListeners.remove(listener); - } - } - - void addUnderflowListener(UnderflowListener listener) { - synchronized (underflowListeners) { - underflowListeners.add(listener); - } - } - - void removeUnderflowListener(UnderflowListener listener) { - synchronized (underflowListeners) { - underflowListeners.remove(listener); - } - } - - void addCorkListener(CorkListener listener) { - synchronized (corkListeners) { - corkListeners.add(listener); - } - } - - void removeCorkListener(CorkListener listener) { - synchronized (corkListeners) { - corkListeners.remove(listener); - } - } - - void addPlaybackStartedListener(PlaybackStartedListener listener) { - synchronized (playbackStartedListeners) { - playbackStartedListeners.add(listener); - } - } - - void removePlaybackStartedListener(PlaybackStartedListener listener) { - synchronized (playbackStartedListeners) { - playbackStartedListeners.remove(listener); - } - } - - void addLatencyUpdateListener(LatencyUpdateListener listener) { - synchronized (latencyUpdateListeners) { - latencyUpdateListeners.add(listener); - } - } - - void removeLatencyUpdateListener(LatencyUpdateListener listener) { - synchronized (playbackStartedListeners) { - latencyUpdateListeners.remove(listener); - } - } - - void addMovedListener(MovedListener listener) { - synchronized (movedListeners) { - movedListeners.add(listener); - } - } - - void removeMovedListener(MovedListener listener) { - synchronized (movedListeners) { - movedListeners.remove(listener); - } - } - - void addSuspendedListener(SuspendedListener listener) { - synchronized (suspendedListeners) { - suspendedListeners.add(listener); - } - } - - void removeSuspendedListener(SuspendedListener listener) { - synchronized (suspendedListeners) { - suspendedListeners.remove(listener); - } - } - - long getState() { - return checkNativeStreamState(native_pa_stream_get_state()); - } - - byte[] getContextPointer() { - return native_pa_stream_get_context(); - } - - int getSinkInputIndex() { - return native_pa_stream_get_index(); - } - - /** - * - * @return the index of the sink or source this stream is connected to in - * the server - */ - int getDeviceIndex() { - return native_pa_stream_get_device_index(); - } - - private void setBufAttr() { - synchronized(bufAttrMutex) { - bufAttr = native_pa_stream_get_buffer_attr(); - } - } - - @SuppressWarnings("unused") - private void bufferAttrCallback() { - setBufAttr(); - } - - int getBufferSize() { - synchronized (bufAttrMutex) { - return bufAttr.getMaxLength(); - } - } - - /** - * - * @return the name of the sink or source this stream is connected to in the - * server - */ - String getDeviceName() { - return native_pa_stream_get_device_name(); - } - - /** - * if the sink or source this stream is connected to has been suspended. - * - * @return - */ - boolean isSuspended() { - return (native_pa_stream_is_suspended() != 0); - } - - /** - * Connect the stream to a sink - * - * @param deviceName - * the device to connect to. use - * null -#include - -/* - * Throw an exception by name - */ -void throwByName(JNIEnv* env, const char* name, const char* msg) { - jclass cls = (*env)->FindClass(env, name); - if (cls != NULL) { - (*env)->ThrowNew(env, cls, msg); - return; - } -} - -jint getJavaIntField(JNIEnv* env, jobject obj, char* fieldName) { - jclass cls = (*env)->GetObjectClass(env, obj); - assert(cls); - jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "I"); - assert(fid); - jint value = (*env)->GetIntField(env, obj, fid); - return value; -} - -void setJavaIntField(JNIEnv *env, jobject obj, char *fieldName, jint value) { - jclass cls = (*env)->GetObjectClass(env, obj); - assert(cls); - jfieldID fid =(*env)->GetFieldID(env, cls, fieldName, "I"); - assert(fid); - (*env)->SetIntField(env, obj, fid, value); -} - -jlong getJavaLongField(JNIEnv* env, jobject obj, char* name) { - jclass cls = (*env)->GetObjectClass(env, obj); - assert(cls); - jfieldID fid = (*env)->GetFieldID(env, cls, name, "J"); - assert(fid); - jint value = (*env)->GetLongField(env, obj, fid); - return value; - -} - -void setJavaLongField(JNIEnv* env, jobject obj, char* name, jlong value) { - jclass cls = (*env)->GetObjectClass(env, obj); - assert(cls); - jfieldID fid =(*env)->GetFieldID(env, cls, name, "J"); - assert(fid); - (*env)->SetLongField(env, obj, fid, value); -} - -jbyteArray getJavaByteArrayField(JNIEnv* env, jobject obj, char* name) { - - jclass cls = (*env)->GetObjectClass(env, obj); - assert(cls); - jfieldID fid = (*env)->GetFieldID(env, cls, name, "[B"); - assert(fid); - jbyteArray array = (*env)->GetObjectField(env, obj, fid); - assert(array); - return array; - -} - -void setJavaByteArrayField(JNIEnv* env, jobject obj, char* name, - jbyteArray array) { - - jclass cls = (*env)->GetObjectClass(env, obj); - assert(cls); - jfieldID fid = (*env)->GetFieldID(env, cls, name, "[B"); - assert(fid); - - (*env)->SetObjectField(env, obj, fid, array); - return; -} - -void callJavaVoidMethod(JNIEnv* env, jobject obj, const char* method_name) { - - jclass cls = (*env)->GetObjectClass(env, obj); - if (cls == NULL) { - printf("unable to get class of object"); - return; - } - jmethodID mid = (*env)->GetMethodID(env, cls, method_name, "()V"); - if (mid == NULL) { - printf("unable to get method %s\n", method_name); - return; - - } - (*env)->CallVoidMethod(env, obj, mid); - - return; - -} - -jobject getLockObject(JNIEnv* env) { - - const char* eventLoopClassName = - "org/classpath/icedtea/pulseaudio/EventLoop"; - - jclass eventLoopClass = (*env)->FindClass(env, eventLoopClassName); - assert(eventLoopClass); - - const char* getEventLoopIDSignature = - "()Lorg/classpath/icedtea/pulseaudio/EventLoop;"; - jmethodID getEventLoopID = (*env)->GetStaticMethodID(env, eventLoopClass, "getEventLoop", - getEventLoopIDSignature); - assert(getEventLoopID); - - jobject eventLoop = (*env)->CallStaticObjectMethod(env, eventLoopClass, getEventLoopID); - assert(eventLoop); - - jfieldID lockID = (*env)->GetFieldID(env, eventLoopClass, "threadLock", - "Ljava/lang/Object;"); - assert(lockID); - - jobject lockObject = (*env)->GetObjectField(env, eventLoop, lockID); - assert(lockObject); - return lockObject; - -} - -void notifyWaitingOperations(JNIEnv* env) { - jobject lockObject = getLockObject(env); - - (*env)->MonitorEnter(env, lockObject); - - jclass objectClass = (*env)->FindClass(env, "java/lang/Object"); - assert(objectClass); - jmethodID notifyAllID = (*env)->GetMethodID(env, objectClass, "notifyAll", "()V"); - assert(notifyAllID); - - (*env)->CallObjectMethod(env, lockObject, notifyAllID); - - (*env)->MonitorExit(env, lockObject); - -} - -void* getJavaPointer(JNIEnv* env, jobject obj, char* name) { - - jbyteArray array = getJavaByteArrayField(env, obj, name); - assert(array); - void* value = convertJavaPointerToNative(env, array); - // allow returning NULL values - return value; -} - -void setJavaPointer(JNIEnv* env, jobject obj, char* name, void* value) { - - // allow NULL for value - jbyteArray array = convertNativePointerToJava(env, value); - assert(array); - setJavaByteArrayField(env, obj, name, array); - return; -} - -void* convertJavaPointerToNative(JNIEnv* env, jbyteArray pointer) { - // printf("convertJavaPointerToNative(): entering method\n"); - - void* returnPointer = NULL; - - // this is not the pointer, but the container of the pointer - assert(pointer); - - jsize len = (*env)->GetArrayLength(env, pointer); - assert(len); - assert(len == sizeof(returnPointer)); - - jbyte* data = (*env)->GetByteArrayElements(env, pointer, NULL); - if (data == NULL) { - return NULL; // oome; - } - memcpy(&returnPointer, data, sizeof(returnPointer)); - (*env)->ReleaseByteArrayElements(env, pointer, data, 0); - - // printf("convertJavaPointerToNative(): leaving method\n"); - return returnPointer; -} - -jbyteArray convertNativePointerToJava(JNIEnv* env, void* pointer) { - // printf("convertNativePointerToJava(): entering method\n"); - - jbyteArray array = (*env)->NewByteArray(env, sizeof(pointer)); - if (array == NULL) { - return 0; // oome? - } - - jbyte* data = (*env)->GetByteArrayElements(env, array, NULL); - if (data == NULL) { - return 0; // oome - } - - memcpy(data, &pointer, sizeof(pointer)); - (*env)->ReleaseByteArrayElements(env, array, data, 0); - - // printf("convertNativePointerToJava(): leaving method\n"); - - return array; -} - diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/native/jni-common.h --- a/pulseaudio/src/native/jni-common.h Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* jni-common.h - Copyright (C) 2008 Red Hat, Inc. - - This file is part of IcedTea. - - IcedTea is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, version 2. - - IcedTea is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with IcedTea; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. - - Linking this library statically or dynamically with other modules is - making a combined work based on this library. Thus, the terms and - conditions of the GNU General Public License cover the whole - combination. - - As a special exception, the copyright holders of this library give you - permission to link this library with independent modules to produce an - executable, regardless of the license terms of these independent - modules, and to copy and distribute the resulting executable under - terms of your choice, provided that you also meet, for each linked - independent module, the terms and conditions of the license of that - module. An independent module is a module which is not derived from - or based on this library. If you modify this library, you may extend - this exception to your version of the library, but you are not - obligated to do so. If you do not wish to do so, delete this - exception statement from your version. - */ - -#ifndef _JNI_COMMON_H -#define _JNI_COMMON_H - -#include - -/* - * This file contains some commonly used functions - * - */ - -// Sets the field with name field_name from jclass clz to pa_prefix_field_name. -#define SET_JAVA_STATIC_LONG_FIELD_TO_PA_ENUM(env, clz, java_prefix, pa_prefix, name) \ - do { \ - char *java_full_name = #java_prefix #name; \ - jfieldID fid = (*env)->GetStaticFieldID(env, clz, java_full_name, "J"); \ - assert(fid); \ - (*env)->SetStaticLongField(env, clz, fid, PA_##pa_prefix##_##name); \ - } while(0); - -typedef struct java_context_t { - JNIEnv* env; - jobject obj; -} java_context_t; - -/* Exception Handling */ - -void throwByName(JNIEnv* const env, const char* const name, - const char* const msg); - -#define ILLEGAL_ARGUMENT_EXCEPTION "java/lang/IllegalArgumentException" -#define ILLEGAL_STATE_EXCEPTION "java/lang/IllegalStateException" - -/* Threading and Synchronization */ - -jobject getLockObject(JNIEnv* env); -void notifyWaitingOperations(JNIEnv* env); - -/* Storing and Loading Values */ - -jint getJavaIntField(JNIEnv* env, jobject obj, char* fieldName); -void setJavaIntField(JNIEnv* env, jobject obj, char* fieldName, jint value); - -jlong getJavaLongField(JNIEnv* env, jobject obj, char* name); -void setJavaLongField(JNIEnv* env, jobject, char* name, jlong value); - -jbyteArray getJavaByteArrayField(JNIEnv* env, jobject obj, char* name); -void setJavaByteArrayField(JNIEnv* env, jobject obj, char* name, - jbyteArray array); - -/* Pointers and Java */ - -void* getJavaPointer(JNIEnv* env, jobject obj, char* name); -void setJavaPointer(JNIEnv* env, jobject obj, char*name, void* pointer_value); - -void* convertJavaPointerToNative(JNIEnv* env, jbyteArray pointer); -jbyteArray convertNativePointerToJava(JNIEnv* env, void* pointer); - -/* Calling Java Functions */ - -void callJavaVoidMethod(JNIEnv* env, jobject obj, const char* method_name); - -#endif - diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/native/org_classpath_icedtea_pulseaudio_ContextEvent.c --- a/pulseaudio/src/native/org_classpath_icedtea_pulseaudio_ContextEvent.c Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* org_classpath_icedtea_pulseaudio_EventLoop.c - Copyright (C) 2011 Red Hat, Inc. - - This file is part of IcedTea. - - IcedTea is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, version 2. - - IcedTea is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with IcedTea; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. - - Linking this library statically or dynamically with other modules is - making a combined work based on this library. Thus, the terms and - conditions of the GNU General Public License cover the whole - combination. - - As a special exception, the copyright holders of this library give you - permission to link this library with independent modules to produce an - executable, regardless of the license terms of these independent - modules, and to copy and distribute the resulting executable under - terms of your choice, provided that you also meet, for each linked - independent module, the terms and conditions of the license of that - module. An independent module is a module which is not derived from - or based on this library. If you modify this library, you may extend - this exception to your version of the library, but you are not - obligated to do so. If you do not wish to do so, delete this - exception statement from your version. - */ - -#include - -#include "org_classpath_icedtea_pulseaudio_ContextEvent.h" -#include "jni-common.h" - -// we don't prefix the java names with anything, so we leave the third argument -// empty -#define SET_CONTEXT_ENUM(env, clz, name) \ - SET_JAVA_STATIC_LONG_FIELD_TO_PA_ENUM(env, clz, , CONTEXT, name) - -/* - * Class: org_classpath_icedtea_pulseaudio_ContextEvent - * Method: init_constants - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_ContextEvent_init_1constants - (JNIEnv *env, jclass clz) { - SET_CONTEXT_ENUM(env, clz, UNCONNECTED); - SET_CONTEXT_ENUM(env, clz, CONNECTING); - SET_CONTEXT_ENUM(env, clz, AUTHORIZING); - SET_CONTEXT_ENUM(env, clz, SETTING_NAME); - SET_CONTEXT_ENUM(env, clz, READY); - SET_CONTEXT_ENUM(env, clz, FAILED); - SET_CONTEXT_ENUM(env, clz, TERMINATED); -} - diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/native/org_classpath_icedtea_pulseaudio_EventLoop.c --- a/pulseaudio/src/native/org_classpath_icedtea_pulseaudio_EventLoop.c Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,297 +0,0 @@ -/* org_classpath_icedtea_pulseaudio_EventLoop.c - Copyright (C) 2008 Red Hat, Inc. - - This file is part of IcedTea. - - IcedTea is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, version 2. - - IcedTea is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with IcedTea; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. - - Linking this library statically or dynamically with other modules is - making a combined work based on this library. Thus, the terms and - conditions of the GNU General Public License cover the whole - combination. - - As a special exception, the copyright holders of this library give you - permission to link this library with independent modules to produce an - executable, regardless of the license terms of these independent - modules, and to copy and distribute the resulting executable under - terms of your choice, provided that you also meet, for each linked - independent module, the terms and conditions of the license of that - module. An independent module is a module which is not derived from - or based on this library. If you modify this library, you may extend - this exception to your version of the library, but you are not - obligated to do so. If you do not wish to do so, delete this - exception statement from your version. - */ - -#include - -#include "org_classpath_icedtea_pulseaudio_EventLoop.h" -#include "jni-common.h" - -#include - -const int PA_ITERATE_BLOCK = 1; -const int PA_ITERATE_NOBLOCK = 0; - -static java_context_t* java_context = NULL; - -JNIEnv* pulse_thread_env = NULL; - -void sink_list_success_cb(pa_context *context, const pa_sink_info *i, int eol, - void *userdata) { - - if (eol == 0) { - jclass cls = (*pulse_thread_env)->GetObjectClass(pulse_thread_env, - java_context->obj); - assert(cls); - jstring name = (*pulse_thread_env)->NewStringUTF(pulse_thread_env, i->name); - assert(name); - jmethodID mid1 = (*pulse_thread_env)->GetMethodID(pulse_thread_env, cls, - "sink_callback", "(Ljava/lang/String;)V"); - assert(mid1); - (*pulse_thread_env)->CallVoidMethod(pulse_thread_env, - java_context->obj, mid1, name) ; - } else { - assert(pulse_thread_env); - notifyWaitingOperations(pulse_thread_env); - } - -} - -void source_list_success_cb(pa_context *context, const pa_source_info *i, - int eol, void *userdata) { - - if (eol == 0) { - jclass cls = (*pulse_thread_env)->GetObjectClass(pulse_thread_env, - java_context->obj); - assert(cls); - jstring name = (*pulse_thread_env)->NewStringUTF(pulse_thread_env, i->name); - assert(name); - jmethodID mid1 = (*pulse_thread_env)->GetMethodID(pulse_thread_env, cls, - "source_callback", "(Ljava/lang/String;)V"); - assert(mid1); - (*pulse_thread_env)->CallVoidMethod(pulse_thread_env, - java_context->obj, mid1, name) ; - } else { - assert(pulse_thread_env); - notifyWaitingOperations(pulse_thread_env); - } - -} - -static void context_change_callback(pa_context* context, void* userdata) { - assert(context); - assert(userdata == NULL); - - //java_context_t* java_context = (java_context_t*)userdata; - JNIEnv* env = java_context->env; - jobject obj = java_context->obj; - - // printf("context state changed to %d\n", pa_context_get_state(context)); - - /* Call the EventLoop.update method in java - * to handle all java-side events - */ - jclass cls = (*env)->GetObjectClass(env, obj); - assert(cls); - jmethodID mid = (*env)->GetMethodID(env, cls, "update", "(J)V"); - assert(mid); - (*env)->CallVoidMethod(env, obj, mid, (jlong) pa_context_get_state(context)); - return; - -} - -static int poll_function(struct pollfd *ufds, unsigned long nfds, int timeout, - void *userdata) { - - JNIEnv* env = pulse_thread_env; - assert(env); - jobject lockObject = getLockObject(env); - - (*env)->MonitorExit(env, lockObject); - - int value = poll(ufds, nfds, timeout); - - (*env)->MonitorEnter(env, lockObject); - return value; -} - -/* - * Class: org_classpath_icedtea_pulseaudio_EventLoop - * Method: native_setup - * Signature: (Ljava/lang/String;Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_EventLoop_native_1setup -(JNIEnv* env, jobject obj, jstring appName, jstring server) { - - assert(appName != NULL); - - // printf("native_setup() called\n"); - pa_mainloop *mainloop = pa_mainloop_new(); - assert(mainloop != NULL); - pa_mainloop_api *mainloop_api = pa_mainloop_get_api(mainloop); - assert(mainloop != NULL); - - pa_context *context = NULL; - - const char* string_appName; - string_appName = (*env)->GetStringUTFChars(env, appName, NULL); - if (string_appName == NULL) { - return; /* a OutOfMemoryError thrown by vm */ - } - // printf("using appName : %s\n", string_appName); - context = pa_context_new(mainloop_api, string_appName); - assert(mainloop != NULL); - (*env)->ReleaseStringUTFChars(env, appName, string_appName); - - obj = (*env)->NewGlobalRef(env, obj); - - java_context = malloc(sizeof(java_context_t)); - java_context->env = env; - pulse_thread_env = env; - java_context->obj = obj; - - pa_context_set_state_callback(context, context_change_callback, NULL); - - if (server != NULL) { - /* obtain the server from the caller */ - const char* string_server = NULL; - string_server = (*env)->GetStringUTFChars(env, server, NULL); - if (string_server == NULL) { - /* error, so clean up */ - (*env)->DeleteGlobalRef(env, java_context->obj); - pa_context_disconnect(context); - pa_mainloop_free(mainloop); - free(java_context); - return; /* OutOfMemoryError */ - } - // printf("About to connect to server: %s\n", string_server); - pa_context_connect(context, string_server, 0, NULL); - (*env)->ReleaseStringUTFChars(env, appName, string_server); - } else { - // printf("using default server\n"); - pa_context_connect(context, NULL, 0, NULL); - } - - // set polling function - pa_mainloop_set_poll_func(mainloop, poll_function, NULL); - - setJavaPointer(env, obj, "mainloopPointer", mainloop); - setJavaPointer(env, obj, "contextPointer", context); - // printf("native_setup() returning\n"); - return; - -} -/* - * Class: org_classpath_icedtea_pulseaudio_EventLoop - * Method: native_iterate - * Signature: (I)I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_EventLoop_native_1iterate -(JNIEnv* env, jobject obj, jint timeout) { - - pa_mainloop* mainloop = (pa_mainloop*) getJavaPointer(env, obj, "mainloopPointer"); - assert(mainloop); - - int returnval; - - returnval = pa_mainloop_prepare(mainloop, timeout); - if ( returnval < 0) { - return -1; - } - returnval = pa_mainloop_poll(mainloop); - if ( returnval < 0) { - return -1; - } - returnval = pa_mainloop_dispatch(mainloop); - if ( returnval < 0) { - return -1; - } - return returnval; - -} - -/* - * Class: org_classpath_icedtea_pulseaudio_EventLoop - * Method: nativeUpdateTargetPortNameList - * Signature: ()[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_EventLoop_nativeUpdateTargetPortNameList -(JNIEnv* env, jobject obj) { - - pa_context* context = (pa_context*) getJavaPointer(env, obj, "contextPointer"); - assert(context); - pa_operation *o = pa_context_get_sink_info_list(context, sink_list_success_cb, NULL); - assert(o); - return convertNativePointerToJava(env, o); -} - - -/* - * Class: org_classpath_icedtea_pulseaudio_EventLoop - * Method: nativeUpdateSourcePortNameList - * Signature: ()[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_EventLoop_nativeUpdateSourcePortNameList -(JNIEnv * env, jobject obj) { - pa_context* context = (pa_context*) getJavaPointer(env, obj, "contextPointer"); - assert(context); - pa_operation *o = pa_context_get_source_info_list(context, source_list_success_cb, NULL); - assert(o); - return convertNativePointerToJava(env, o); -} - -static void context_drain_complete_callback(pa_context* context, void* userdata) { - pa_context_disconnect(context); - -} - -/* - * Class: org_classpath_icedtea_pulseaudio_EventLoop - * Method: native_shutdown - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_EventLoop_native_1shutdown -(JNIEnv *env, jobject obj) { - - // printf("native_shutdown() starting\n"); - - pa_mainloop* mainloop = (pa_mainloop*) getJavaPointer(env, obj, "mainloopPointer"); - assert(mainloop != NULL); - - pa_context* context = (pa_context*) getJavaPointer(env, obj, "contextPointer"); - assert(context != NULL); - - pa_operation* o = pa_context_drain(context, context_drain_complete_callback, NULL); - if ( o == NULL) { - pa_context_disconnect(context); - pa_mainloop_free(mainloop); - } else { - pa_operation_unref(o); - } - - pa_context_unref(context); - (*env)->DeleteGlobalRef(env, java_context->obj); - - free(java_context); - java_context = NULL; - - setJavaPointer(env, obj, "mainloopPointer", NULL); - setJavaPointer(env, obj, "contextPointer", NULL); - - // printf("native_shutdown() returning\n"); - -} - diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/native/org_classpath_icedtea_pulseaudio_Operation.c --- a/pulseaudio/src/native/org_classpath_icedtea_pulseaudio_Operation.c Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* org_classpath_icedtea_pulseaudio_Operation.c - Copyright (C) 2008 Red Hat, Inc. - - This file is part of IcedTea. - - IcedTea is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, version 2. - - IcedTea is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with IcedTea; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. - - Linking this library statically or dynamically with other modules is - making a combined work based on this library. Thus, the terms and - conditions of the GNU General Public License cover the whole - combination. - - As a special exception, the copyright holders of this library give you - permission to link this library with independent modules to produce an - executable, regardless of the license terms of these independent - modules, and to copy and distribute the resulting executable under - terms of your choice, provided that you also meet, for each linked - independent module, the terms and conditions of the license of that - module. An independent module is a module which is not derived from - or based on this library. If you modify this library, you may extend - this exception to your version of the library, but you are not - obligated to do so. If you do not wish to do so, delete this - exception statement from your version. - */ - -#include "org_classpath_icedtea_pulseaudio_Operation.h" - -#include "jni-common.h" -#include - -// we don't prefix the java names with anything, so we leave the third argument -// empty -#define SET_OP_ENUM(env, clz, name) \ - SET_JAVA_STATIC_LONG_FIELD_TO_PA_ENUM(env, clz, , OPERATION, name) - -/* - * Class: org_classpath_icedtea_pulseaudio_Operation - * Method: init_constants - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_Operation_init_1constants - (JNIEnv *env, jclass clz) { - SET_OP_ENUM(env, clz, RUNNING); - SET_OP_ENUM(env, clz, DONE); - SET_OP_ENUM(env, clz, CANCELLED); -} - - -/* - * Class: org_classpath_icedtea_pulseaudio_Operation - * Method: native_ref - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_Operation_native_1ref -(JNIEnv* env, jobject obj) { - - pa_operation* operation = (pa_operation*) getJavaPointer(env, obj, "operationPointer"); - assert(operation); - pa_operation_ref(operation); - -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Operation - * Method: native_unref - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_Operation_native_1unref -(JNIEnv* env, jobject obj) { - - pa_operation* operation = (pa_operation*) getJavaPointer(env, obj, "operationPointer"); - assert(operation); - pa_operation_unref(operation); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Operation - * Method: native_get_state - * Signature: ()I - */ -JNIEXPORT jlong JNICALL Java_org_classpath_icedtea_pulseaudio_Operation_native_1get_1state -(JNIEnv *env, jobject obj) { - - pa_operation* operation = (pa_operation*) getJavaPointer(env, obj, "operationPointer"); - assert(operation); - jlong state = pa_operation_get_state(operation); - return state; -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/native/org_classpath_icedtea_pulseaudio_PulseAudioSourcePort.c --- a/pulseaudio/src/native/org_classpath_icedtea_pulseaudio_PulseAudioSourcePort.c Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -#include "org_classpath_icedtea_pulseaudio_PulseAudioSourcePort.h" -#include "jni-common.h" -#include -#include - -typedef struct java_context { - JNIEnv* env; - jobject obj; -} java_context; - -extern JNIEnv* pulse_thread_env; - -void source_callback(pa_context *context, int success, void *userdata) { - assert(context); - assert(pulse_thread_env); - notifyWaitingOperations(pulse_thread_env); -} - -void get_source_volume_callback(pa_context *context, const pa_source_info *i, - int eol, void *userdata) { - assert(context); - assert(pulse_thread_env); - - if (eol == 0) { - // printf("%s\n", i->name); - jobject obj = (jobject) userdata; - assert(obj); - jclass cls = (*pulse_thread_env)->GetObjectClass(pulse_thread_env, obj); - assert(cls); - jmethodID mid1 = (*pulse_thread_env)->GetMethodID(pulse_thread_env, cls, - "update_channels_and_volume", "(IF)V"); - assert(mid1); - (*pulse_thread_env)->CallVoidMethod(pulse_thread_env, obj, mid1, - (int) (i->volume).channels, (float) (i->volume).values[0]) ; - } else { - notifyWaitingOperations(pulse_thread_env); - } -} - -/* - * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourcePort - * Method: native_update_volume - * Signature: ()[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourcePort_native_1update_1volume -(JNIEnv *env, jobject obj) { - jclass cls = (*env)->GetObjectClass(env, obj); - assert(cls); - jfieldID fid = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;"); - assert(fid); - jstring jstr = (*env)->GetObjectField(env, obj, fid); - assert(jstr); - const char *name = (*env)->GetStringUTFChars(env, jstr, NULL); - if (name == NULL) { - return NULL; // oome - } - - pa_context* context = (pa_context*) getJavaPointer(env, obj, "contextPointer"); - assert(context); - obj = (*env)->NewGlobalRef(env, obj); - pa_operation *o = pa_context_get_source_info_by_name (context, (char*) name, get_source_volume_callback, obj); - assert(o); - return convertNativePointerToJava(env, o); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourcePort - * Method: native_set_volume - * Signature: (F)[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourcePort_native_1set_1volume -(JNIEnv *env, jobject obj, jfloat value) { - jclass cls = (*env)->GetObjectClass(env, obj); - assert(cls); - - jfieldID fid = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;"); - assert(fid); - - jstring jstr = (*env)->GetObjectField(env, obj, fid); - assert(jstr); - - const char *name = (*env)->GetStringUTFChars(env, jstr, NULL); - if (name == NULL) { - return NULL; // oome - } - - pa_context* context = (pa_context*) getJavaPointer(env, obj, "contextPointer"); - assert(context); - - obj = (*env)->NewGlobalRef(env, obj); - fid = (*env)->GetFieldID(env, cls, "channels", "I"); - assert(fid); - - jint channels = (*env)->GetIntField(env, obj, fid); - pa_cvolume cv; - - pa_operation *o = pa_context_set_source_volume_by_name (context, (char*) name,pa_cvolume_set(&cv, channels, value), source_callback, obj); - assert(o); - - return convertNativePointerToJava(env, o); -} - diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/native/org_classpath_icedtea_pulseaudio_PulseAudioTargetPort.c --- a/pulseaudio/src/native/org_classpath_icedtea_pulseaudio_PulseAudioTargetPort.c Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -#include "org_classpath_icedtea_pulseaudio_PulseAudioTargetPort.h" - -#include "jni-common.h" -#include -#include - -typedef struct java_context { - JNIEnv* env; - jobject obj; -} java_context; - -extern JNIEnv* pulse_thread_env; - -static void sink_callback(pa_context *context, int success, void *userdata) { - notifyWaitingOperations(pulse_thread_env); -} - -static void get_sink_volume_callback(pa_context *context, const pa_sink_info *i, - int eol, void *userdata) { - assert(context); - assert(pulse_thread_env); - - if (eol == 0) { - // printf("%s\n", i->name); - jobject obj = (jobject) userdata; - assert(obj); - jclass cls = (*pulse_thread_env)->GetObjectClass(pulse_thread_env, obj); - assert(cls); - jmethodID mid1 = (*pulse_thread_env)->GetMethodID(pulse_thread_env, cls, - "update_channels_and_volume", "(IF)V"); - assert(mid1); - (*pulse_thread_env)->CallVoidMethod(pulse_thread_env, obj, mid1, - (int) (i->volume).channels, (float) (i->volume).values[0]) ; - } else { - notifyWaitingOperations(pulse_thread_env); - } - -} - - -/* - * Class: org_classpath_icedtea_pulseaudio_PulseAudioTargetPort - * Method: native_update_volume - * Signature: ()[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioTargetPort_native_1update_1volume -(JNIEnv *env, jobject obj) { - jclass cls = (*env)->GetObjectClass(env, obj); - assert(cls); - - jfieldID fid = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;"); - assert(fid); - - jstring jstr = (*env)->GetObjectField(env, obj, fid); - assert(jstr); - - const char *name = (*env)->GetStringUTFChars(env, jstr, NULL); - if (name == NULL) { - return NULL; // oome - } - - pa_context* context = (pa_context*) getJavaPointer(env, obj, "contextPointer"); - assert(context); - - obj = (*env)->NewGlobalRef(env, obj); - - pa_operation *o = pa_context_get_sink_info_by_name (context, (char*) name, get_sink_volume_callback, obj); - assert(o); - - return convertNativePointerToJava(env, o); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_PulseAudioTargetPort - * Method: native_set_volume - * Signature: (F)[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioTargetPort_native_1set_1volume -(JNIEnv *env, jobject obj, jfloat value) { - jclass cls = (*env)->GetObjectClass(env, obj); - assert(cls); - - jfieldID fid = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;"); - assert(fid); - - jstring jstr = (*env)->GetObjectField(env, obj, fid); - assert(jstr); - - const char *name = (*env)->GetStringUTFChars(env, jstr, NULL); - if (name == NULL) { - return NULL; // return oome - } - - pa_context* context = (pa_context*) getJavaPointer(env, obj, "contextPointer"); - assert(context); - - obj = (*env)->NewGlobalRef(env, obj); - fid = (*env)->GetFieldID(env, cls, "channels", "I"); - assert(fid); - - jint channels = (*env)->GetIntField(env, obj, fid); - pa_cvolume cv; - pa_operation *o = pa_context_set_sink_volume_by_name (context, (char*) name,pa_cvolume_set(&cv, channels, value), sink_callback, obj); - assert(o); - - return convertNativePointerToJava(env, o); -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/src/native/org_classpath_icedtea_pulseaudio_Stream.c --- a/pulseaudio/src/native/org_classpath_icedtea_pulseaudio_Stream.c Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1103 +0,0 @@ -#include "org_classpath_icedtea_pulseaudio_Stream.h" - -#include "jni-common.h" -#include -#include - -#define STREAM_POINTER "streamPointer" -#define CONTEXT_POINTER "contextPointer" - -typedef struct java_context { - JNIEnv* env; - jobject obj; -} java_context; - -extern JNIEnv* pulse_thread_env; - -static void set_sink_input_volume_callback(pa_context* context, int success, - void* userdata) { - notifyWaitingOperations(pulse_thread_env); - -} - -const char* getStringFromFormat(pa_sample_format_t format) { - - const char* value; - - if (format == PA_SAMPLE_U8) { - value = "PA_SAMPLE_U8"; - } else if (format == PA_SAMPLE_ALAW) { - value = "PA_SAMPLE_ALAW"; - } else if (format == PA_SAMPLE_ULAW) { - value = "PA_SAMPLE_ULAW"; - } else if (format == PA_SAMPLE_S16BE) { - value = "PA_SAMPLE_S16BE"; - } else if (format == PA_SAMPLE_S16LE) { - value = "PA_SAMPLE_S16LE"; - } else if (format == PA_SAMPLE_S32BE) { - value = "PA_SAMPLE_S32BE"; - } else if (format == PA_SAMPLE_S32LE) { - value = "PA_SAMPLE_S32LE"; - } else { - value = "PA_SAMPLE_INVALID"; - } - - return value; -} - -pa_sample_format_t getFormatFromString(const char* encoding) { - - pa_sample_format_t format; - - if (strcmp(encoding, "PA_SAMPLE_U8") == 0) { - format = PA_SAMPLE_U8; - } else if (strcmp(encoding, "PA_SAMPLE_ALAW") == 0) { - format = PA_SAMPLE_ALAW; - } else if (strcmp(encoding, "PA_SAMPLE_ULAW;") == 0) { - format = PA_SAMPLE_ULAW; - } else if (strcmp(encoding, "PA_SAMPLE_S16BE") == 0) { - format = PA_SAMPLE_S16BE; - } else if (strcmp(encoding, "PA_SAMPLE_S16LE") == 0) { - format = PA_SAMPLE_S16LE; - } else if (strcmp(encoding, "PA_SAMPLE_S32BE") == 0) { - format = PA_SAMPLE_S32BE; - } else if (strcmp(encoding, "PA_SAMPLE_S32LE") == 0) { - format = PA_SAMPLE_S32LE; - } else { - format = PA_SAMPLE_INVALID; - } - - return format; -} - -static void stream_state_callback(pa_stream* stream, void *userdata) { - //printf("stream_state_callback called\n"); - - java_context* context = userdata; - assert(stream); - assert(context); - assert(context->env); - assert(context->obj); - - if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { - callJavaVoidMethod(context->env, context->obj, "stateCallback"); - } else { - callJavaVoidMethod(pulse_thread_env, context->obj, "stateCallback"); - } - -} - -static void stream_write_callback(pa_stream *stream, size_t length, - void *userdata) { - // printf("stream_write_callback called\n"); - - java_context* context = userdata; - assert(stream); - assert(context); - assert(context->env); - assert(context->obj); - - if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { - callJavaVoidMethod(context->env, context->obj, "writeCallback"); - } else { - callJavaVoidMethod(pulse_thread_env, context->obj, "writeCallback"); - } -} - -static void stream_read_callback(pa_stream *stream, size_t length, - void *userdata) { - // printf("stream_read_callback called\n"); - - java_context* context = userdata; - assert(stream); - assert(context); - assert(context->env); - assert(context->obj); - - if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { - callJavaVoidMethod(context->env, context->obj, "readCallback"); - } else { - callJavaVoidMethod(pulse_thread_env, context->obj, "readCallback"); - } - -} - -static void stream_overflow_callback(pa_stream *stream, void *userdata) { - //printf("stream_overflow_callback called\n"); - - java_context* context = userdata; - assert(stream); - assert(context); - assert(context->env); - assert(context->obj); - - if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { - callJavaVoidMethod(context->env, context->obj, "overflowCallback"); - } else { - callJavaVoidMethod(pulse_thread_env, context->obj, "overflowCallback"); - } -} - -static void stream_underflow_callback(pa_stream *stream, void *userdata) { - // printf("stream_underflow_callback called\n"); - - java_context* context = userdata; - assert(stream); - assert(context); - assert(context->env); - assert(context->obj); - - if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { - callJavaVoidMethod(context->env, context->obj, "underflowCallback"); - } else { - callJavaVoidMethod(pulse_thread_env, context->obj, "underflowCallback"); - } -} - - -static void update_timing_info_callback(pa_stream* stream, int success, void* userdata) { - - assert(stream); - JNIEnv* env = pulse_thread_env; - assert(env); - - notifyWaitingOperations(env); - - if (success == 0) { - throwByName(env, ILLEGAL_STATE_EXCEPTION, "drain failed"); - } - -} - -// requires pulseaudio 0.9.11 :( -static void stream_started_callback(pa_stream *stream, void *userdata) { - // printf("stream_started_callback called\n"); - java_context* context = userdata; - assert(stream); - assert(context); - assert(context->env); - assert(context->obj); - - if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { - callJavaVoidMethod(context->env, context->obj, - "playbackStartedCallback"); - } else { - callJavaVoidMethod(pulse_thread_env, context->obj, - "playbackStartedCallback"); - } - -} - -static void stream_latency_update_callback(pa_stream *stream, void *userdata) { - // printf("stream_latency_update_callback called\n"); - - java_context* context = userdata; - assert(stream); - assert(context); - assert(context->env); - assert(context->obj); - - if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { - callJavaVoidMethod(context->env, context->obj, "latencyUpdateCallback"); - } else { - callJavaVoidMethod(pulse_thread_env, context->obj, - "latencyUpdateCallback"); - } -} - -static void stream_moved_callback(pa_stream *stream, void *userdata) { - // printf("stream_moved_callback called\n"); - - java_context* context = userdata; - assert(stream); - assert(context); - assert(context->env); - assert(context->obj); - - if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { - callJavaVoidMethod(context->env, context->obj, "movedCallback"); - } else { - callJavaVoidMethod(pulse_thread_env, context->obj, "movedCallback"); - } - -} - -static void stream_suspended_callback(pa_stream *stream, void *userdata) { - // printf("stream_suspended_callback called\n"); - - java_context* context = userdata; - assert(stream); - assert(context); - assert(context->env); - assert(context->obj); - - if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { - callJavaVoidMethod(context->env, context->obj, "suspendedCallback"); - } else { - callJavaVoidMethod(pulse_thread_env, context->obj, "suspendedCallback"); - } - -} - -static void buf_attr_changed_callback(pa_stream *stream, void *userdata) { - java_context* context = userdata; - assert(stream); - assert(context); - assert(context->env); - assert(context->obj); - - if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { - callJavaVoidMethod(context->env, context->obj, "bufferAttrCallback"); - } else { - callJavaVoidMethod(pulse_thread_env, context->obj, "bufferAttrCallback"); - } -} - -// used to set stream flags and states. -// The names in Stream.java have a {STATE_,FLAG_} prefix, but we don't want to -// add the underscore in every line in init_constants, so we add it here. If -// constants with no prefix are ever introduced (i.e. java_prefix is "", -// it's important to remove the ##_ ) -#define SET_STREAM_ENUM(env, clz, java_prefix, state_name) \ - SET_JAVA_STATIC_LONG_FIELD_TO_PA_ENUM(env, clz, java_prefix##_, STREAM, state_name) - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: init_constants - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_init_1constants - (JNIEnv *env, jclass clz) { - // set states. - SET_STREAM_ENUM(env, clz, STATE, UNCONNECTED); - SET_STREAM_ENUM(env, clz, STATE, CREATING); - SET_STREAM_ENUM(env, clz, STATE, READY); - SET_STREAM_ENUM(env, clz, STATE, FAILED); - SET_STREAM_ENUM(env, clz, STATE, TERMINATED); - - // set flags. - SET_STREAM_ENUM(env, clz, FLAG, NOFLAGS); - SET_STREAM_ENUM(env, clz, FLAG, START_CORKED); - SET_STREAM_ENUM(env, clz, FLAG, INTERPOLATE_TIMING); - SET_STREAM_ENUM(env, clz, FLAG, NOT_MONOTONIC); - SET_STREAM_ENUM(env, clz, FLAG, AUTO_TIMING_UPDATE); - SET_STREAM_ENUM(env, clz, FLAG, NO_REMAP_CHANNELS); - SET_STREAM_ENUM(env, clz, FLAG, NO_REMIX_CHANNELS); - SET_STREAM_ENUM(env, clz, FLAG, FIX_FORMAT); - SET_STREAM_ENUM(env, clz, FLAG, FIX_RATE); - SET_STREAM_ENUM(env, clz, FLAG, FIX_CHANNELS); - SET_STREAM_ENUM(env, clz, FLAG, DONT_MOVE); - SET_STREAM_ENUM(env, clz, FLAG, VARIABLE_RATE); - SET_STREAM_ENUM(env, clz, FLAG, PEAK_DETECT); - SET_STREAM_ENUM(env, clz, FLAG, START_MUTED); - SET_STREAM_ENUM(env, clz, FLAG, ADJUST_LATENCY); - SET_STREAM_ENUM(env, clz, FLAG, EARLY_REQUESTS); - SET_STREAM_ENUM(env, clz, FLAG, DONT_INHIBIT_AUTO_SUSPEND); - SET_STREAM_ENUM(env, clz, FLAG, START_UNMUTED); - SET_STREAM_ENUM(env, clz, FLAG, FAIL_ON_SUSPEND); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_new - * Signature: ([BLjava/lang/String;Ljava/lang/String;II)V - */ -JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1new -(JNIEnv* env, jobject obj, jbyteArray contextPointer, jstring nameString, - jstring encodingString, jint sampleRate, jint channels) { - - // printf("creating a new PulseAudio stream\n"); - - java_context* j_context = malloc(sizeof(java_context)); - assert(j_context); - j_context->env = env; - j_context->obj = (*env)->NewGlobalRef(env, obj); - - setJavaPointer(env, obj, CONTEXT_POINTER, j_context); - - pa_context* context = convertJavaPointerToNative(env, contextPointer); - assert(context); - - const char* name = NULL; - if (nameString) { - name = (*env)->GetStringUTFChars(env,nameString, NULL); - if (name == NULL) { - (*env)->DeleteGlobalRef(env, obj); - free(j_context); - return; // oome thrown - } - } - - const char *encoding = (*env)->GetStringUTFChars(env, encodingString, NULL); - if( encoding == NULL) { - return; //oome thrown - } - - pa_sample_spec sample_spec; - - sample_spec.format = getFormatFromString(encoding); - sample_spec.rate = sampleRate; - sample_spec.channels = channels; - - if ( !pa_sample_spec_valid(&sample_spec)) { - throwByName(env, "java/lang/IllegalArgumentException", "Invalid format"); - (*env)->ReleaseStringUTFChars(env, encodingString, encoding); - if (name) { - (*env)->ReleaseStringUTFChars(env, nameString,name); - } - return; - } - - pa_stream* stream = pa_stream_new(context, name, &sample_spec, NULL); - assert(stream); - if (name) { - (*env)->ReleaseStringUTFChars(env, nameString,name); - } - - setJavaPointer(env, obj, STREAM_POINTER, stream); - - /* - * - * The stream has been created; now setup the callbacks - * so we can do somethig about them - * - */ - - pa_stream_set_state_callback (stream, stream_state_callback, j_context); - pa_stream_set_write_callback (stream, stream_write_callback, j_context); - pa_stream_set_read_callback (stream, stream_read_callback, j_context); - pa_stream_set_overflow_callback (stream, stream_overflow_callback, j_context); - pa_stream_set_underflow_callback (stream, stream_underflow_callback, j_context); - pa_stream_set_started_callback (stream, stream_started_callback, j_context); - pa_stream_set_latency_update_callback (stream, stream_latency_update_callback, j_context); - pa_stream_set_moved_callback (stream, stream_moved_callback, j_context); - pa_stream_set_suspended_callback (stream, stream_suspended_callback, j_context); - pa_stream_set_buffer_attr_callback(stream, buf_attr_changed_callback, j_context); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_unref - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1unref -(JNIEnv* env, jobject obj) { - - java_context* j_context = getJavaPointer(env, obj, CONTEXT_POINTER); - assert(j_context); - (*env)->DeleteGlobalRef(env, j_context->obj); - free(j_context); - setJavaPointer(env, obj, CONTEXT_POINTER, NULL); - - pa_stream* stream = getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - pa_stream_unref(stream); - setJavaPointer(env, obj, STREAM_POINTER, NULL); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_get_state - * Signature: ()I - */ -JNIEXPORT jlong JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1get_1state -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - return pa_stream_get_state(stream); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_get_context - * Signature: ()[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1get_1context -(JNIEnv* env, jobject obj) { - - pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - pa_context* context = pa_stream_get_context(stream); - assert(context); - return convertNativePointerToJava(env, context); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_get_index - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1get_1index -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - return pa_stream_get_index(stream); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_get_device_index - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1get_1device_1index -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - return pa_stream_get_device_index(stream); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_get_device_name - * Signature: ()Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1get_1device_1name -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - const char* name = pa_stream_get_device_name(stream); - assert(name); - return (*env)->NewStringUTF(env, name); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_is_suspended - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1is_1suspended -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - return pa_stream_is_suspended(stream); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_connect_playback - * Signature: (Ljava/lang/String;IIIIII[B[B)I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1connect_1playback -(JNIEnv* env, jobject obj, jstring device, jint bufferMaxLength, - jint bufferTargetLength, jint bufferPreBuffering, - jint bufferMinimumRequest, jint bufferFragmentSize, jlong flags, - jbyteArray volumePointer, jbyteArray sync_streamPointer) { - pa_stream *sync_stream; - if(sync_streamPointer != NULL) { - sync_stream = convertJavaPointerToNative(env, sync_streamPointer); - printf("Master stream is %p\n", sync_stream); - } else { - sync_stream = NULL; - } - - pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, STREAM_POINTER); - - pa_buffer_attr buffer_attr; - - memset(&buffer_attr, 0, sizeof(buffer_attr)); - - buffer_attr.maxlength = (uint32_t) bufferMaxLength; - buffer_attr.tlength = (uint32_t) bufferTargetLength; - buffer_attr.prebuf = (uint32_t) bufferPreBuffering; - buffer_attr.minreq = (uint32_t) bufferMinimumRequest; - - const char* dev = NULL; - if (device != NULL) { - dev = (*env)->GetStringUTFChars(env, device, NULL); - if (dev == NULL) { - return -1; // oome thrown - } - } - - int value = pa_stream_connect_playback(stream, dev, &buffer_attr, - (pa_stream_flags_t) flags, NULL, sync_stream); - - if (dev != NULL) { - (*env)->ReleaseStringUTFChars(env, device, dev); - dev = NULL; - } - return value; -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_connect_record - * Signature: (Ljava/lang/String;IIIIII[B[B)I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1connect_1record -(JNIEnv* env, jobject obj, jstring device, jint bufferMaxLength, - jint bufferTargetLength, jint bufferPreBuffereing, - jint bufferMinimumRequest, jint bufferFragmentSize, jlong flags, - jbyteArray volumePointer, jbyteArray sync_streamPointer) { - - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - - pa_buffer_attr buffer_attr; - memset(&buffer_attr, 0 , sizeof(buffer_attr)); - buffer_attr.maxlength = (uint32_t) bufferMaxLength; - buffer_attr.fragsize = (uint32_t) bufferFragmentSize; - - const char* dev = NULL; - if (device != NULL) { - dev = (*env)->GetStringUTFChars(env, device, NULL); - if (dev == NULL) { - return -1; // oome thrown - } - } - - int value = pa_stream_connect_record(stream, dev, &buffer_attr, - (pa_stream_flags_t) flags); - - if (dev != NULL) { - (*env)->ReleaseStringUTFChars(env, device, dev); - dev = NULL; - } - return value; - -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_disconnect - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1disconnect -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - int return_value = pa_stream_disconnect(stream); - - return return_value; -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_write - * Signature: ([BI)I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1write -(JNIEnv* env, jobject obj, jbyteArray data, jint offset, jint data_length) { - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - jbyte* data_buffer = (*env)->GetByteArrayElements(env, data, NULL); - if (data_buffer == NULL) { - return -1; // oome thrown - } - jbyte* buffer_start = data_buffer + offset; - int value = pa_stream_write(stream, buffer_start, data_length, NULL, 0, PA_SEEK_RELATIVE); - (*env)->ReleaseByteArrayElements(env, data, data_buffer, 0); - return value; -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_peek - * Signature: ()[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1peek -(JNIEnv* env, jobject obj) { - - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - const void* startLocation; - size_t count; - - if ( pa_stream_peek(stream, &startLocation, &count) < 0 ) { - return NULL; - } - - /* no data available */ - if (startLocation == NULL) { - return NULL; - } - - jsize length = count; - jbyteArray data = (*env)->NewByteArray(env, length); - - if ( data == NULL) { - return NULL; // oome thrown - } - - (*env)->SetByteArrayRegion(env, data, 0, count, startLocation); - return data; -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_drop - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1drop -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - return pa_stream_drop(stream); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_writable_size - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1writable_1size -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - if(!stream) { - return 0; - } - size_t size = pa_stream_writable_size(stream); - return size; - -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_readable_size - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1readable_1size -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - return pa_stream_readable_size(stream); -} - -static void drain_callback(pa_stream* stream, int success, void* userdata) { - - assert(stream); - JNIEnv* env = pulse_thread_env; - assert(env); - - notifyWaitingOperations(env); - - if (success == 0) { - throwByName(env, ILLEGAL_STATE_EXCEPTION, "drain failed"); - } - -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_drain - * Signature: ()[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1drain -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - pa_operation* operation = pa_stream_drain(stream, drain_callback, NULL); - assert(operation); - return convertNativePointerToJava(env, operation); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_is_corked - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1is_1corked -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - return pa_stream_is_corked(stream); -} - -static void cork_callback(pa_stream* stream, int success, void* userdata) { - - assert(stream); - JNIEnv* env = pulse_thread_env; - assert(env); - notifyWaitingOperations(env); - - if (success == 0) { - throwByName(env, ILLEGAL_STATE_EXCEPTION, "cork failed"); - } - -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_cork - * Signature: (I)[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1cork -(JNIEnv* env, jobject obj, jint yes) { - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - pa_operation* operation = pa_stream_cork(stream, yes, cork_callback, NULL); - assert(operation); - return convertNativePointerToJava(env, operation); -} - -static void flush_callback(pa_stream* stream, int success, void* userdata) { - assert(stream); - JNIEnv* env = pulse_thread_env; - assert(env); - notifyWaitingOperations(env); - - if (success == 0) { - throwByName(env, ILLEGAL_STATE_EXCEPTION, "flush failed"); - } - -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_flush - * Signature: ()[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1flush -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - pa_operation* operation = pa_stream_flush(stream, flush_callback, NULL); - assert(operation); - return convertNativePointerToJava(env, operation); -} - -static void trigger_callback(pa_stream* stream, int success, void* userdata) { - assert(stream); - JNIEnv* env = pulse_thread_env; - assert(env); - notifyWaitingOperations(env); - - if (success == 0) { - throwByName(env, ILLEGAL_STATE_EXCEPTION, "trigger failed"); - } - -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_trigger - * Signature: ()[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1trigger -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - pa_operation* operation = pa_stream_trigger(stream, trigger_callback, NULL); - assert(operation); - return convertNativePointerToJava(env, operation); -} - -static void set_name_callback(pa_stream* stream, int success, void* userdata) { - assert(stream); - JNIEnv* env = pulse_thread_env; - notifyWaitingOperations(env); - - if (success == 0) { - throwByName(env, ILLEGAL_STATE_EXCEPTION, "set_name failed"); - } -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_set_name - * Signature: (Ljava/lang/String;)[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1set_1name -(JNIEnv* env, jobject obj, jstring newName) { - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - - const char* name; - name = (*env)->GetStringUTFChars(env, newName, NULL); - if (name == NULL) { - return 0; // OutOfMemoryError already thrown - } - - pa_operation* operation = pa_stream_set_name(stream, name, set_name_callback, NULL); - assert(operation); - (*env)->ReleaseStringUTFChars(env, newName, name); - - return convertNativePointerToJava(env, operation); -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_get_time - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1get_1time -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - - pa_usec_t time = 0; - int result = pa_stream_get_time (stream,&time); - assert(result == 0); - - return time; - -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_get_latency - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1get_1latency -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - pa_usec_t returnValue = 0; - int negative = 0; - int result = pa_stream_get_latency ( stream, &returnValue, &negative); - assert(result == 0); - assert(negative == 0); - return returnValue; -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_get_sample_spec - * Signature: ()Lorg/classpath/icedtea/pulseaudio/StreamSampleSpecification; - */ -JNIEXPORT jobject JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1get_1sample_1spec -(JNIEnv* env, jobject obj) { - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - - const pa_sample_spec* sample_spec = pa_stream_get_sample_spec(stream); - assert(sample_spec); - - char* name = "Lorg/classpath/icedtea/pulseaudio/StreamSampleSpecification;"; - jclass cls = (*env)->FindClass(env, name); - assert(cls); - jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "", "V"); - assert(constructor_mid); - - const char* formatString = getStringFromFormat(sample_spec->format); - assert(formatString); - int rate = sample_spec->rate; - int channels = sample_spec->channels; - - jstring format = (*env)->NewStringUTF(env, formatString); - if ( format == NULL) { - return NULL; // oome - } - jobject return_object = (*env)->NewObject(env, cls, constructor_mid, format, rate, channels); - - return return_object; -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_get_buffer_attr - * Signature: ()Lorg/classpath/icedtea/pulseaudio/StreamBufferAttributes; - */ -JNIEXPORT jobject JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1get_1buffer_1attr -(JNIEnv* env, jobject obj) { - - // printf("in native_pa_stream_get_buffer_attributes"); - - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - const pa_buffer_attr* buffer = pa_stream_get_buffer_attr(stream); - assert(buffer); - - const char* class_name = "org/classpath/icedtea/pulseaudio/StreamBufferAttributes"; - jclass cls = (*env)->FindClass(env, class_name); - assert(cls); - jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "", "(IIIII)V"); - assert(constructor_mid); - jint maxLength = buffer->maxlength; - jint targetLength = buffer->tlength; - jint preBuffering = buffer->prebuf; - jint minimumRequest = buffer->minreq; - jint fragmentSize = buffer->fragsize; - - jobject return_object = (*env)->NewObject(env, cls, constructor_mid, maxLength, targetLength, - preBuffering, minimumRequest, fragmentSize); - - return return_object; -} - -static void set_buffer_attr_callback(pa_stream* stream, int success, - void* userdata) { - - assert(stream); - JNIEnv* env = pulse_thread_env; - assert(env); - notifyWaitingOperations(env); - - if (success == 0) { - throwByName(env, ILLEGAL_STATE_EXCEPTION, "set_buffer_attr failed"); - } -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_set_buffer_attr - * Signature: (Lorg/classpath/icedtea/pulseaudio/StreamBufferAttributes;)[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1set_1buffer_1attr -(JNIEnv* env, jobject obj, jobject bufferAttributeObject) { - - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - - jclass cls = (*env)->GetObjectClass(env, bufferAttributeObject); - assert(cls); - - pa_buffer_attr buffer; - - jmethodID getMaxLengthID = (*env)->GetMethodID(env,cls,"getMaxLength","()I"); - assert(getMaxLengthID); - buffer.maxlength = (uint32_t) (*env)->CallIntMethod(env, bufferAttributeObject, getMaxLengthID); - - jmethodID getTargetLengthID = (*env)->GetMethodID(env,cls,"getTargetLength","()I"); - assert(getTargetLengthID); - buffer.tlength = (uint32_t) (*env)->CallIntMethod(env, bufferAttributeObject, getTargetLengthID); - - jmethodID getPreBufferingID = (*env)->GetMethodID(env,cls,"getPreBuffering","()I"); - assert(getPreBufferingID); - buffer.prebuf = (uint32_t) (*env)->CallIntMethod(env, bufferAttributeObject, getPreBufferingID); - - jmethodID getMinimumRequestID = (*env)->GetMethodID(env, cls, "getMinimumRequest", "()I"); - assert(getMinimumRequestID); - buffer.minreq = (uint32_t) (*env)->CallIntMethod(env, bufferAttributeObject, getMinimumRequestID ); - - jmethodID getFragmentSizeID = (*env)->GetMethodID(env,cls,"getFragmentSize","()I"); - assert(getFragmentSizeID); - buffer.fragsize = (uint32_t) (*env)->CallIntMethod(env, bufferAttributeObject, getFragmentSizeID ); - - /* - const pa_buffer_attr* old_buffer = pa_stream_get_buffer_attr(stream); - - printf("old buffer values: %u %u %u %u %u\n", old_buffer->maxlength, old_buffer->tlength, old_buffer->prebuf, old_buffer->minreq, old_buffer->fragsize); - - printf("want these values: %u %u %u %u %u\n", buffer.maxlength, buffer.tlength, buffer.prebuf, buffer.minreq, buffer.fragsize); - */ - - pa_operation* operation = pa_stream_set_buffer_attr(stream, &buffer, set_buffer_attr_callback, NULL); - - assert(operation); - return convertNativePointerToJava(env,operation); -} - -static void update_sample_rate_callback(pa_stream* stream, int success, - void* userdata) { - assert(stream); - JNIEnv* env = pulse_thread_env; - assert(env); - notifyWaitingOperations(env); - - if (success == 0) { - throwByName(env, ILLEGAL_STATE_EXCEPTION, "update_sampl_rate failed"); - } - -} -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_pa_stream_update_sample_rate - * Signature: (I)[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1update_1sample_1rate -(JNIEnv* env, jobject obj, jint newRate) { - - uint32_t rate = (uint32_t) newRate; - - pa_stream* stream = (pa_stream*)getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - pa_operation* operation = pa_stream_update_sample_rate(stream,rate, update_sample_rate_callback, NULL); - assert(operation); - return convertNativePointerToJava(env, operation); - -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_set_volume - * Signature: (F)[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1set_1volume -(JNIEnv *env, jobject obj, jfloat new_volume) { - - pa_stream *stream = getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - pa_context *context = pa_stream_get_context(stream); - assert(context); - - int stream_id = pa_stream_get_index(stream); - int channels = pa_stream_get_sample_spec(stream)->channels; - pa_cvolume cv; - - pa_operation* o = pa_context_set_sink_input_volume(context, stream_id, pa_cvolume_set(&cv, channels, new_volume), set_sink_input_volume_callback, NULL); - assert(o); - - return convertNativePointerToJava(env, o); - -} - - -static void get_sink_input_volume_callback(pa_context *context, const pa_sink_input_info *i, - int eol, void *userdata) { - - JNIEnv* env = pulse_thread_env; - - assert(context); - assert(env); - jobject obj = (jobject) userdata; - assert(obj); - - if (eol == 0) { - jclass cls = (*pulse_thread_env)->GetObjectClass(pulse_thread_env, obj); - assert(cls); - jmethodID mid1 = (*pulse_thread_env)->GetMethodID(pulse_thread_env, cls, - "update_channels_and_volume", "(IF)V"); - assert(mid1); - (*pulse_thread_env)->CallVoidMethod(pulse_thread_env, obj, mid1, - (int) (i->volume).channels, (float) (i->volume).values[0]) ; - } else { - notifyWaitingOperations(pulse_thread_env); - (*env)->DeleteGlobalRef(env, obj); - } -} - -/* - * Class: org_classpath_icedtea_pulseaudio_Stream - * Method: native_update_volume - * Signature: ()[B - */ -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1update_1volume -(JNIEnv* env, jobject obj) { - - pa_stream* stream = getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - - int sink_input_index = pa_stream_get_index(stream); - - pa_context* context = pa_stream_get_context(stream); - assert(context); - - obj = (*env)->NewGlobalRef(env, obj); - pa_operation *o = pa_context_get_sink_input_info(context, sink_input_index , get_sink_input_volume_callback, obj); - assert(o); - return convertNativePointerToJava(env, o); - - -} - -JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_bytesInBuffer(JNIEnv *env, jobject obj) { - pa_stream *stream = getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - const pa_timing_info *timing_info = pa_stream_get_timing_info(stream); - int write_index = timing_info->write_index; - int read_index = timing_info->read_index; - return write_index - read_index; -} - -JNIEXPORT jbyteArray JNICALL Java_org_classpath_icedtea_pulseaudio_Stream_native_1pa_1stream_1updateTimingInfo(JNIEnv* env, jobject obj) { - pa_stream *stream = getJavaPointer(env, obj, STREAM_POINTER); - assert(stream); - pa_operation* o = pa_stream_update_timing_info(stream, update_timing_info_callback, NULL); - assert(o); - return convertNativePointerToJava(env, o); - -} - - - diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/testsounds/README --- a/pulseaudio/testsounds/README Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -The sound files (startup.wav and logout.wav) were taken from the KDE Project -(www.kde.org). A copy of them can be obtained from -http://websvn.kde.org/branches/KDE/4.0/kdeartwork/sounds/ . They are licensed -by the copyright holders as GPLv2. \ No newline at end of file diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/unittests/org/classpath/icedtea/pulseaudio/OtherSoundProvidersAvailableTest.java --- a/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/OtherSoundProvidersAvailableTest.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* OtherSoundProvidersAvailableTest.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; -import javax.sound.sampled.SourceDataLine; - -import org.junit.Test; - -public class OtherSoundProvidersAvailableTest { - - @Test - public void testOtherSoundProviders() { - System.out.println("This tests if alsa mixers are still available"); - - Mixer.Info mixerInfos[] = AudioSystem.getMixerInfo(); - Mixer.Info selectedMixerInfo = null; - Mixer mixer; - - boolean selected = false; - int i = 0; - System.out.println("Available Mixers:"); - // use 0,0 or the default - for (Mixer.Info info : mixerInfos) { - System.out.println("Mixer Line " + i++ + ": " + info.getName() - + " " + info.getDescription()); - if (info.getName().contains("0,0") && !selected) { - System.out.println("^ selecting as the mixer to use"); - selectedMixerInfo = info; - selected = true; - } - } - - if (selectedMixerInfo != null) { - System.out.println(selectedMixerInfo.toString()); - } - - System.out.print("Selected mixer is of class: "); - - mixer = AudioSystem.getMixer(selectedMixerInfo); - System.out.println(mixer.getClass().toString()); - try { - Line.Info sourceDataLineInfo = null; - - mixer.open(); // initialize the mixer - - Line.Info allLineInfo[] = mixer.getSourceLineInfo(); - System.out.println("Source lines supported by mixer: "); - int j = 0; - for (Line.Info lineInfo : allLineInfo) { - System.out.println("Source Line " + j++ + ": " - + lineInfo.getLineClass()); - if (lineInfo.toString().contains("SourceDataLine")) { - sourceDataLineInfo = lineInfo; - } - - } - - if (sourceDataLineInfo == null) { - System.out.println("Mixer supports no SourceDataLines"); - } else { - SourceDataLine sourceDataLine = (SourceDataLine) mixer - .getLine(sourceDataLineInfo); - - sourceDataLine.open(); - // sourceDataLine.write('a', 0, 2); - sourceDataLine.close(); - } - } catch (LineUnavailableException e) { - System.out.println("Line unavailable"); - } finally { - mixer.close(); - } - - } -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java --- a/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,637 +0,0 @@ -/* PulseAudioClipTest.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.io.File; -import java.io.IOException; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Clip; -import javax.sound.sampled.Control; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; -import javax.sound.sampled.UnsupportedAudioFileException; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class PulseAudioClipTest { - - Mixer mixer; - AudioFormat aSupportedFormat = new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 1, 1, 44100f, true); - - int started = 0; - int stopped = 0; - int opened = 0; - int closed = 0; - - @Before - public void setUp() throws LineUnavailableException { - Mixer.Info wantedMixerInfo = null; - Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo(); - for (Mixer.Info mixerInfo : mixerInfos) { - if (mixerInfo.getName().contains("PulseAudio")) { - wantedMixerInfo = mixerInfo; - break; - } - } - assert (wantedMixerInfo != null); - mixer = AudioSystem.getMixer(wantedMixerInfo); - mixer.open(); - - started = 0; - stopped = 0; - opened = 0; - closed = 0; - } - - @Test - public void testObtainingAClip() throws LineUnavailableException { - System.out - .println("This tests if a clip can be obtained from the mixer"); - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - Assert.assertNotNull(clip); - } - - @Test(expected = IllegalArgumentException.class) - public void testClipOpenWrongUse() throws LineUnavailableException { - System.out.println("This test checks "); - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - clip.open(); - } - - @Test - public void testClipOpens() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - clip.open(audioInputStream); - clip.close(); - } - - @Test - public void testOpenCloseLotsOfTimes() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - for (int i = 0; i < 1000; i++) { - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - clip.open(audioInputStream); - clip.close(); - } - } - - @Test - public void testLoop4Times() throws LineUnavailableException, IOException, - UnsupportedAudioFileException { - System.out - .println("This tests loop(4) on the Clip. " - + "You should hear a certain part of the clip play back 5 time"); - - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - clip.open(audioInputStream); - - clip.setLoopPoints((int) (clip.getFrameLength() / 4), (int) (clip - .getFrameLength() / 2)); - clip.loop(4); - - clip.drain(); - - clip.stop(); - - clip.close(); - } - - - @Test - public void testLoopContinuously() throws LineUnavailableException, - IOException, UnsupportedAudioFileException, InterruptedException { - System.out - .println("This tests loop(LOOP_CONTINUOUSLY) on the Clip"); - final Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - File soundFile = new File("testsounds/error.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - clip.open(audioInputStream); - - clip.setLoopPoints((int) (clip.getFrameLength() / 4), (int) (clip - .getFrameLength() / 2)); - clip.loop(Clip.LOOP_CONTINUOUSLY); - - Runnable blocker = new Runnable() { - - @Override - public void run() { - clip.drain(); - } - - }; - - Thread th = new Thread(blocker); - th.start(); - th.join(10000); - - if (!th.isAlive()) { - clip.close(); - Assert.fail("LOOP_CONTINUOUSLY doesnt seem to work"); - } - - clip.stop(); - th.join(500); - if ( th.isAlive()) { - clip.close(); - Assert.fail("stopping LOOP_CONTINUOSLY failed"); - } - - clip.close(); - } - - @Test - public void testIsActiveAndIsOpen() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - - Assert.assertFalse(clip.isActive()); - Assert.assertFalse(clip.isOpen()); - clip.open(audioInputStream); - Assert.assertTrue(clip.isOpen()); - Assert.assertFalse(clip.isActive()); - clip.start(); - Assert.assertTrue(clip.isOpen()); - Assert.assertTrue(clip.isActive()); - clip.stop(); - Assert.assertTrue(clip.isOpen()); - Assert.assertFalse(clip.isActive()); - clip.close(); - Assert.assertFalse(clip.isOpen()); - Assert.assertFalse(clip.isActive()); - - } - - @Test - public void testOpenEvent() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - System.out - .println("This tests the OPEN event. You should see an OPEN on the next line"); - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - - opened = 0; - - LineListener openListener = new LineListener() { - - @Override - public void update(LineEvent event) { - if (event.getType() == LineEvent.Type.OPEN) { - System.out.println("OPEN"); - opened++; - } - } - - }; - - clip.addLineListener(openListener); - clip.open(audioInputStream); - clip.close(); - clip.removeLineListener(openListener); - - Assert.assertEquals(1, opened); - - } - - @Test - public void testCloseEvent() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - - System.out.println("This tests the CLOSE event"); - - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - - closed = 0; - - LineListener closeListener = new LineListener() { - - @Override - public void update(LineEvent event) { - if (event.getType() == LineEvent.Type.CLOSE) { - System.out.println("CLOSE"); - closed++; - } - } - - }; - - clip.addLineListener(closeListener); - clip.open(audioInputStream); - clip.close(); - - clip.removeLineListener(closeListener); - - Assert.assertEquals(1, closed); - - } - - @Test - public void testStartedStopped() throws LineUnavailableException, - UnsupportedAudioFileException, IOException, InterruptedException { - - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - Clip clip; - clip = (Clip) mixer.getLine(new DataLine.Info(Clip.class, audioFormat)); - Assert.assertNotNull(clip); - - clip.open(audioInputStream); - - LineListener startStopListener = new LineListener() { - - @Override - public void update(LineEvent event) { - if (event.getType() == LineEvent.Type.START) { - System.out.println("START"); - started++; - Assert.assertEquals(1, started); - } - - if (event.getType() == LineEvent.Type.STOP) { - System.out.println("STOP"); - stopped++; - Assert.assertEquals(1, stopped); - } - } - - }; - - clip.addLineListener(startStopListener); - - clip.start(); - clip.drain(); - clip.stop(); - clip.close(); - - Assert.assertEquals(1, started); - Assert.assertEquals(1, stopped); - - } - - @Test(timeout = 1000) - public void testDrainWithoutStart() throws UnsupportedAudioFileException, - IOException, LineUnavailableException { - - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - Clip clip; - clip = (Clip) mixer.getLine(new DataLine.Info(Clip.class, audioFormat)); - Assert.assertNotNull(clip); - - clip.open(audioInputStream); - clip.drain(); - clip.close(); - - } - - @Test - public void testDrainBlocksWhilePlaying() - throws UnsupportedAudioFileException, IOException, - LineUnavailableException { - - String fileName = "testsounds/startup.wav"; - File soundFile = new File(fileName); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - Clip clip; - clip = (Clip) mixer.getLine(new DataLine.Info(Clip.class, audioFormat)); - Assert.assertNotNull(clip); - - long startTime = System.currentTimeMillis(); - - clip.open(audioInputStream); - clip.start(); - clip.drain(); - clip.stop(); - clip.close(); - - long endTime = System.currentTimeMillis(); - - Assert.assertTrue(endTime - startTime > 3000); - System.out.println("Playback of " + fileName + " completed in " - + (endTime - startTime) + " milliseconds"); - } - - @Test - public void testLoop0InterruptsPlayback() throws LineUnavailableException, - IOException, UnsupportedAudioFileException { - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - clip.open(audioInputStream); - - clip.setLoopPoints((int) (clip.getFrameLength() / 4), (int) (clip - .getFrameLength() / 2)); - clip.loop(4); - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - clip.loop(0); - clip.close(); - } - - @Test(expected = IllegalArgumentException.class) - public void testOpenWrongUse() throws LineUnavailableException { - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - clip.open(); - - } - - /* - * - * modified version of the sample code at - * http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=173 - * - */ - - @Test - public void testPlayTwoClips() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - Clip clip1 = (Clip) mixer.getLine(new Line.Info(Clip.class)); - File soundFile1 = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream1 = AudioSystem - .getAudioInputStream(soundFile1); - clip1.open(audioInputStream1); - - Clip clip2 = (Clip) mixer.getLine(new Line.Info(Clip.class)); - File soundFile2 = new File("testsounds/logout.wav"); - AudioInputStream audioInputStream2 = AudioSystem - .getAudioInputStream(soundFile2); - clip2.open(audioInputStream2); - - clip1.start(); - clip2.start(); - - clip1.drain(); - clip2.drain(); - - clip1.close(); - clip2.close(); - - Assert.assertFalse(clip1.isOpen()); - Assert.assertFalse(clip2.isOpen()); - - } - - @Test - public void testSupportedControls() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - File soundFile1 = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream1 = AudioSystem - .getAudioInputStream(soundFile1); - clip.open(audioInputStream1); - - Control[] controls = clip.getControls(); - Assert.assertNotNull(controls); - Assert.assertTrue(controls.length >= 1); - for (Control control : controls) { - Assert.assertNotNull(control); - } - - clip.close(); - } - - @Test - public void testFramePositionBeforeClose() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - System.out - .println("This tests if the Clip provides the correct frame position"); - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - String fileName = "testsounds/logout.wav"; - File soundFile1 = new File(fileName); - AudioInputStream audioInputStream1 = AudioSystem - .getAudioInputStream(soundFile1); - clip.open(audioInputStream1); - - clip.start(); - - clip.drain(); - - long pos = clip.getFramePosition(); - - clip.close(); - - long expected = 136703; - long granularity = 5; - System.out.println("Frames in " + fileName + ": " + expected); - System.out.println("Frame position in clip :" + pos); - Assert.assertTrue("Expected: " + expected + " got " + pos, Math - .abs(expected - pos) < granularity); - - } - - @Test - public void testFramePositionWithStartStop() - throws LineUnavailableException, UnsupportedAudioFileException, - IOException, InterruptedException { - - System.out - .println("This tests if the Clip provides the correct frame position"); - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - String fileName = "testsounds/logout.wav"; - File soundFile1 = new File(fileName); - AudioInputStream audioInputStream1 = AudioSystem - .getAudioInputStream(soundFile1); - clip.open(audioInputStream1); - - clip.start(); - - Thread.sleep(500); - clip.stop(); - Thread.sleep(5000); - clip.start(); - - clip.drain(); - - long pos = clip.getFramePosition(); - - clip.close(); - - long expected = 136703; - long granularity = 5; - System.out.println("Frames in " + fileName + ": " + expected); - System.out.println("Frame position in clip :" + pos); - Assert.assertTrue("Expected: " + expected + " got " + pos, Math - .abs(expected - pos) < granularity); - - } - - @Test - public void testFramePositionWithLoop() throws LineUnavailableException, - UnsupportedAudioFileException, IOException, InterruptedException { - System.out.println("This tests if the Clip provides the correct frame " - + "position with a bit of looping in the clip"); - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - String fileName = "testsounds/logout.wav"; - File soundFile1 = new File(fileName); - AudioInputStream audioInputStream1 = AudioSystem - .getAudioInputStream(soundFile1); - clip.open(audioInputStream1); - - clip.setLoopPoints(0, -1); - clip.loop(1); - Thread.sleep(500); - clip.stop(); - Thread.sleep(2000); - clip.start(); - Thread.sleep(100); - clip.stop(); - Thread.sleep(4000); - clip.start(); - Thread.sleep(100); - clip.stop(); - Thread.sleep(2000); - clip.start(); - Thread.sleep(100); - clip.stop(); - Thread.sleep(3000); - clip.start(); - - clip.drain(); - - long pos = clip.getFramePosition(); - - clip.close(); - - long expected = 136703 * 1; - long granularity = 5; - System.out.println("Frames in " + fileName + ": " + expected); - System.out.println("Frame position in clip :" + pos); - Assert.assertTrue("Expected: " + expected + " got " + pos, Math - .abs(expected - pos) < granularity); - - } - - @Test - public void testFramePositionAfterLooping() - throws LineUnavailableException, UnsupportedAudioFileException, - IOException { - System.out - .println("This tests if the Clip provides the correct frame position"); - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - String fileName = "testsounds/logout.wav"; - File soundFile1 = new File(fileName); - AudioInputStream audioInputStream1 = AudioSystem - .getAudioInputStream(soundFile1); - clip.open(audioInputStream1); - - clip.setLoopPoints(0, -1); - clip.loop(1); - - clip.drain(); - - long pos = clip.getFramePosition(); - - clip.close(); - - long expected = 136703 * 2; - long granularity = 5; - System.out.println("Frames in " + fileName + ": " + expected); - System.out.println("Frame position in clip :" + pos); - Assert.assertTrue("Expected: " + expected + " got " + pos, Math - .abs(expected - pos) < granularity); - - } - - @Test - public void testMixerKnowsAboutOpenClips() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); - File soundFile1 = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream1 = AudioSystem - .getAudioInputStream(soundFile1); - - int initiallyOpenClips = mixer.getSourceLines().length; - Assert.assertEquals(initiallyOpenClips, mixer.getSourceLines().length); - clip.open(audioInputStream1); - Assert.assertEquals(initiallyOpenClips + 1, mixer.getSourceLines().length); - Assert.assertEquals(clip, mixer.getSourceLines()[initiallyOpenClips]); - clip.close(); - Assert.assertEquals(initiallyOpenClips, mixer.getSourceLines().length); - - } - - @After - public void tearDown() { - mixer.close(); - - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioEventLoopOverhead.java --- a/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioEventLoopOverhead.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* PulseAudioEventLoopOverhead.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import static org.junit.Assert.assertNotNull; - -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; - -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -public class PulseAudioEventLoopOverhead { - - Mixer mixer; - - @Before - public void setUp() { - Mixer.Info mixerInfos[] = AudioSystem.getMixerInfo(); - Mixer.Info selectedMixerInfo = null; - // int i = 0; - for (Mixer.Info info : mixerInfos) { - // System.out.println("Mixer Line " + i++ + ": " + info.getName() + - // " " + info.getDescription()); - if (info.getName().contains("PulseAudio")) { - selectedMixerInfo = info; - } - } - assertNotNull(selectedMixerInfo); - mixer = AudioSystem.getMixer(selectedMixerInfo); - assertNotNull(mixer); - if (mixer.isOpen()) { - mixer.close(); - } - - } - - @Test - @Ignore - public void testLongWait() throws LineUnavailableException { - mixer.open(); - try { - /* - * While this test is running, the java procces shouldnt be hogging - * the cpu at all - */ - - Thread.sleep(100000); - } catch (InterruptedException e) { - System.out.println("thread interrupted"); - } - - } - - @After - public void tearDown() { - if (mixer.isOpen()) { - mixer.close(); - } - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerProviderTest.java --- a/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerProviderTest.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* PulseAudioMixerProviderTest.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import static org.junit.Assert.assertNotNull; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; -import javax.sound.sampled.SourceDataLine; - -import org.junit.Test; - -public class PulseAudioMixerProviderTest { - - AudioFormat aSupportedFormat = new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 1, 1, 44100f, true); - - @Test - public void testMixerProvider() throws LineUnavailableException { - - System.out - .println("This test checks that the PulseAudio mixer exists and is usable"); - - Mixer selectedMixer = null; - Mixer.Info selectedMixerInfo = null; - - Mixer.Info mixerInfos[] = AudioSystem.getMixerInfo(); - - int i = 0; - for (Mixer.Info info : mixerInfos) { - System.out.println("Mixer Line " + i++ + ": " + info.getName() - + " " + info.getDescription()); - if (info.getName().contains("PulseAudio")) { - System.out.println(" ^ found PulseAudio Mixer!"); - selectedMixerInfo = info; - } - } - - assertNotNull(selectedMixerInfo); - - System.out.println("Getting information from selected mixer:"); - System.out.println("Name: " + selectedMixerInfo.getName()); - System.out.println("Version: " + selectedMixerInfo.getVersion()); - - selectedMixer = AudioSystem.getMixer(selectedMixerInfo); - assertNotNull(selectedMixer); - System.out.println("Implemented in class: " - + selectedMixer.getClass().toString()); - - selectedMixer.open(); // initialize the mixer - - Line.Info sourceDataLineInfo = null; - Line.Info allLineInfo[] = selectedMixer.getSourceLineInfo(); - System.out.println("Source lines supported by mixer: "); - int j = 0; - for (Line.Info lineInfo : allLineInfo) { - System.out.println("Source Line " + j++ + ": " - + lineInfo.getLineClass()); - if (lineInfo.toString().contains("SourceDataLine")) { - sourceDataLineInfo = lineInfo; - } - - } - - if (sourceDataLineInfo == null) { - System.out.println("Mixer supports no SourceDataLines"); - } else { - SourceDataLine sourceDataLine = (SourceDataLine) selectedMixer - .getLine(sourceDataLineInfo); - - sourceDataLine.open(aSupportedFormat); - // sourceDataLine.write('a', 0, 2); - sourceDataLine.close(); - } - - selectedMixer.close(); - - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerRawTest.java --- a/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerRawTest.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* PulseAudioMixerRawTest.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.net.UnknownHostException; - -import javax.sound.sampled.LineUnavailableException; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class PulseAudioMixerRawTest { - - PulseAudioMixer mixer = null; - - @Before - public void setUp() { - mixer = PulseAudioMixer.getInstance(); - if (mixer.isOpen()) { - mixer.close(); - } - } - - @Test - public void testLocalOpen() throws LineUnavailableException { - System.out.println("This test tries to open to the local system"); - mixer.openLocal(); - } - - @Test - public void testLocalOpenAppName() throws LineUnavailableException { - System.out - .println("This test tries to connect to the local system while using an application name"); - mixer.openLocal("JunitTest"); - - } - - @Test(expected = LineUnavailableException.class) - public void testRemoteOpenWithInvalidPort() throws UnknownHostException, - LineUnavailableException { - System.out - .println("this test tries to connect to an invalid remote system"); - mixer.openRemote("JUnitTest", "128.0.0.1", 10); - - } - - /* - * This test assumes a computer named 'town' is in the network with - * pulseaudio listening on port 4173 - */ - @Test - public void testRemoteOpenWithValidPort() throws UnknownHostException, - LineUnavailableException { - System.out.println("This test tries to connect a valid remote system"); - mixer.openRemote("JUnitTest", "town", 4713); - mixer.close(); - } - - /* - * This test assumes a computer named 'town' is in the network with - * pulseaudio listening - */ - @Test - public void testRemoteOpen() throws UnknownHostException, - LineUnavailableException { - mixer.openRemote("JUnitTest", "town"); - mixer.close(); - } - - @Test(expected = LineUnavailableException.class) - public void testInvalidRemoteOpen() throws UnknownHostException, - LineUnavailableException { - mixer.openRemote("JUnitTest", "127.0.0.1"); - mixer.close(); - } - - @After - public void tearDown() { - if (mixer.isOpen()) { - mixer.close(); - } - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerTest.java --- a/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioMixerTest.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,434 +0,0 @@ -/* PulseAudioMixerTest.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; -import javax.sound.sampled.Port; -import javax.sound.sampled.SourceDataLine; -import javax.sound.sampled.TargetDataLine; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -public class PulseAudioMixerTest { - - Mixer selectedMixer; - - AudioFormat aSupportedFormat = new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 1, 1, 44100f, true); - AudioFormat aNotSupportedFormat = new AudioFormat( - AudioFormat.Encoding.ULAW, 44100, 32, 10, 10, 44100f, true); - - @Before - public void setUp() throws Exception { - Mixer.Info mixerInfos[] = AudioSystem.getMixerInfo(); - Mixer.Info selectedMixerInfo = null; - // int i = 0; - for (Mixer.Info info : mixerInfos) { - // System.out.println("Mixer Line " + i++ + ": " + info.getName() + - // " " + info.getDescription()); - if (info.getName().contains("PulseAudio")) { - selectedMixerInfo = info; - } - } - Assert.assertNotNull(selectedMixerInfo); - selectedMixer = AudioSystem.getMixer(selectedMixerInfo); - Assert.assertNotNull(selectedMixer); - if (selectedMixer.isOpen()) { - selectedMixer.close(); - } - - } - - @Test - public void testOpenClose() throws LineUnavailableException { - selectedMixer.open(); - selectedMixer.close(); - - } - - @Test - public void testSourceLinesExist() throws LineUnavailableException { - System.out.println("This tests that source lines exist"); - selectedMixer.open(); - Line.Info allLineInfo[] = selectedMixer.getSourceLineInfo(); - Assert.assertNotNull(allLineInfo); - Assert.assertTrue(allLineInfo.length > 0); - - boolean foundSourceDataLine = false; - boolean foundClip = false; - boolean foundPort = false; - - int j = 0; - for (Line.Info lineInfo : allLineInfo) { - System.out.println("Source Line " + j++ + ": " - + lineInfo.getLineClass()); - if (lineInfo.getLineClass().toString().contains("SourceDataLine")) { - foundSourceDataLine = true; - } else if (lineInfo.getLineClass().toString().contains("Clip")) { - foundClip = true; - } else if (lineInfo.getLineClass().toString().contains("Port")) { - foundPort = true; - } else { - Assert.assertFalse("Found a new type of Line", true); - } - Line sourceLine = (Line) selectedMixer.getLine(lineInfo); - Assert.assertNotNull(sourceLine); - - } - - Assert.assertTrue("Couldnt find a SourceDataLine", foundSourceDataLine); - Assert.assertTrue("Couldnt find a Clip", foundClip); - Assert.assertTrue("Couldnt find a Port", foundPort); - - } - - @Test - public void testTargetLinesExist() throws LineUnavailableException { - System.out.println("This tests if target Lines exist"); - selectedMixer.open(); - Line.Info allLineInfo[] = selectedMixer.getTargetLineInfo(); - Assert.assertNotNull(allLineInfo); - Assert.assertTrue(allLineInfo.length > 0); - - boolean foundTargetDataLine = false; - boolean foundPort = false; - - int j = 0; - for (Line.Info lineInfo : allLineInfo) { - System.out.println("Target Line " + j++ + ": " - + lineInfo.getLineClass()); - if (lineInfo.getLineClass().toString().contains("TargetDataLine")) { - foundTargetDataLine = true; - } else if (lineInfo.getLineClass().toString().contains("Port")) { - foundPort = true; - } else { - Assert.assertTrue("Found invalid type of target line", true); - } - Line targetLine = (Line) selectedMixer.getLine(lineInfo); - Assert.assertNotNull(targetLine); - - } - - Assert.assertTrue("Couldnt find a TargetDataLine", foundTargetDataLine); - Assert.assertTrue("Couldnt find a target Port", foundPort); - - } - - @Ignore - @Test - public void testHeadphonePortExists() throws LineUnavailableException { - selectedMixer.open(); - selectedMixer.getLine(Port.Info.HEADPHONE); - } - - @Ignore - @Test - public void testSpeakerPortExists() throws LineUnavailableException { - selectedMixer.open(); - selectedMixer.getLine(Port.Info.SPEAKER); - } - - @Ignore - @Test - public void testLineInPortExists() throws LineUnavailableException { - selectedMixer.open(); - selectedMixer.getLine(Port.Info.LINE_IN); - } - - @Ignore - @Test - public void testCdPortExists() throws LineUnavailableException { - selectedMixer.open(); - selectedMixer.getLine(Port.Info.COMPACT_DISC); - } - - @Ignore - @Test - public void testLineOutPortExists() throws LineUnavailableException { - selectedMixer.open(); - selectedMixer.getLine(Port.Info.LINE_OUT); - } - - @Ignore - @Test - public void testMicrophonePortExists() throws LineUnavailableException { - selectedMixer.open(); - selectedMixer.getLine(Port.Info.MICROPHONE); - } - - @Test - public void testSaneNumberOfPorts() throws LineUnavailableException { - System.out - .println("This test checks that a sane number of ports are detected"); - selectedMixer.open(); - Line.Info[] lineInfos = selectedMixer.getSourceLineInfo(); - Assert.assertNotNull(lineInfos); - - int ports = 0; - for (Line.Info info : lineInfos) { - if (info instanceof Port.Info) { - ports++; - } - } - Assert.assertTrue("Too few Source ports", ports > 0); - Assert.assertTrue("Too many Source ports... this looks wrong", - ports < 5); - - lineInfos = selectedMixer.getTargetLineInfo(); - ports = 0; - for (Line.Info info : lineInfos) { - if (info instanceof Port.Info) { - ports++; - } - } - Assert.assertTrue("Too few Target ports", ports > 0); - Assert.assertTrue("Too many Target ports... this looks wrong", - ports < 5); - - } - - @Test - public void testGetTargetPortInfo() throws LineUnavailableException { - System.out.println("This test checks target ports"); - selectedMixer.open(); - Line.Info[] lineInfos = selectedMixer.getTargetLineInfo(); - int i = 0; - for (Line.Info info : lineInfos) { - if (info instanceof Port.Info) { - Port.Info portInfo = (Port.Info) info; - Assert.assertTrue(portInfo.isSource() == false); - Assert.assertTrue(portInfo.getLineClass() == Port.class); - System.out.println("Port " + ++i + ": " + portInfo.getName() - + " - " + portInfo.getLineClass()); - } - } - - } - - @Test - public void testGetSourcePortInfo() throws LineUnavailableException { - System.out.println("This test checks source ports"); - selectedMixer.open(); - Line.Info[] lineInfos = selectedMixer.getSourceLineInfo(); - int i = 0; - for (Line.Info info : lineInfos) { - if (info instanceof Port.Info) { - Port.Info portInfo = (Port.Info) info; - Assert.assertTrue(portInfo.isSource() == true); - Assert.assertTrue(portInfo.getLineClass() == Port.class); - System.out.println("Port " + ++i + ": " + portInfo.getName() - + " - " + portInfo.getLineClass()); - } - } - - } - - @Test(expected = IllegalStateException.class) - public void testOpeningAgain() throws LineUnavailableException { - selectedMixer.open(); - selectedMixer.open(); - } - - @Test(expected = IllegalStateException.class) - public void testClosingAgain() throws LineUnavailableException, - IllegalStateException { - selectedMixer.close(); - selectedMixer.close(); - } - - @Test - public void testSourceLinesOpenAndClose() throws LineUnavailableException { - System.out.println("This test checks if source lines open and close"); - selectedMixer.open(); - - Line.Info allLineInfo[] = selectedMixer.getSourceLineInfo(); - for (Line.Info lineInfo : allLineInfo) { - try { - Line sourceLine = selectedMixer.getLine(lineInfo); - sourceLine.open(); - sourceLine.close(); - } catch (IllegalArgumentException e) { - // ignore this - } - } - } - - @Test - public void testTargetLinesOpenAndClose() throws LineUnavailableException { - System.out.println("This test checks if source lines open and close"); - selectedMixer.open(); - - Line.Info allLineInfo[] = selectedMixer.getTargetLineInfo(); - for (Line.Info lineInfo : allLineInfo) { - try { - TargetDataLine targetLine = (TargetDataLine) selectedMixer - .getLine(lineInfo); - Assert.assertNotNull(targetLine); - targetLine.open(aSupportedFormat); - targetLine.close(); - } catch (ClassCastException cce) { - Port targetLine = (Port) selectedMixer.getLine(lineInfo); - Assert.assertNotNull(targetLine); - targetLine.open(); - targetLine.close(); - } - - } - } - - @Test - public void testOpenEvent() throws LineUnavailableException { - LineListener listener = new LineListener() { - private int called = 0; - - @Override - public void update(LineEvent event) { - assert (event.getType() == LineEvent.Type.OPEN); - called++; - // assert listener is called exactly once - Assert.assertEquals(1, called); - } - }; - - selectedMixer.addLineListener(listener); - selectedMixer.open(); - selectedMixer.removeLineListener(listener); - selectedMixer.close(); - - } - - @Test - public void testCloseEvent() throws LineUnavailableException { - LineListener listener = new LineListener() { - private int count = 0; - - @Override - public void update(LineEvent event) { - Assert.assertTrue(event.getType() == LineEvent.Type.CLOSE); - count++; - // assert listener is called exactly once - Assert.assertEquals(1, count); - - } - }; - - selectedMixer.open(); - selectedMixer.addLineListener(listener); - selectedMixer.close(); - selectedMixer.removeLineListener(listener); - - } - - @Test - public void testLineSupportedWorksWithoutOpeningMixer() { - - Assert.assertFalse(selectedMixer.isOpen()); - - Assert.assertFalse(selectedMixer.isLineSupported(new DataLine.Info( - SourceDataLine.class, aNotSupportedFormat))); - - Assert.assertTrue(selectedMixer.isLineSupported(new DataLine.Info( - SourceDataLine.class, aSupportedFormat))); - - } - - @Test - public void testSynchronizationNotSupported() - throws LineUnavailableException { - selectedMixer.open(); - - SourceDataLine line1 = (SourceDataLine) selectedMixer - .getLine(new Line.Info(SourceDataLine.class)); - SourceDataLine line2 = (SourceDataLine) selectedMixer - .getLine(new Line.Info(SourceDataLine.class)); - Line[] lines = { line1, line2 }; - - Assert.assertFalse(selectedMixer - .isSynchronizationSupported(lines, true)); - - Assert.assertFalse(selectedMixer.isSynchronizationSupported(lines, - false)); - - try { - selectedMixer.synchronize(lines, true); - Assert.fail("mixer shouldnt be able to synchronize lines"); - } catch (IllegalArgumentException e) { - - } - - try { - selectedMixer.synchronize(lines, false); - Assert.fail("mixer shouldnt be able to synchronize lines"); - } catch (IllegalArgumentException e) { - - } - - selectedMixer.close(); - - } - - @Ignore - @Test - public void testLongWait() throws LineUnavailableException { - selectedMixer.open(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - System.out.println("thread interrupted"); - } - - } - - @After - public void tearDown() throws Exception { - if (selectedMixer.isOpen()) - selectedMixer.close(); - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLineRawTest.java --- a/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLineRawTest.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,299 +0,0 @@ -/* PulseAudioSourceDataLineRawTest.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.io.File; -import java.io.IOException; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.FloatControl; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; -import javax.sound.sampled.SourceDataLine; -import javax.sound.sampled.UnsupportedAudioFileException; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class PulseAudioSourceDataLineRawTest { - - PulseAudioMixer mixer = null; - - int started = 0; - int stopped = 0; - - AudioFormat aSupportedFormat = new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 1, 1, 44100f, true); - - class ThreadWriter extends Thread { - PulseAudioSourceDataLine line; - AudioInputStream stream; - - public ThreadWriter(AudioInputStream stream, - PulseAudioSourceDataLine line) throws LineUnavailableException { - - this.line = line; - this.stream = stream; - - if (line.isOpen()) { - line.close(); - } - - } - - @Override - public void run() { - try { - AudioFormat audioFormat = stream.getFormat(); - - line.open(audioFormat); - - byte[] abData = new byte[1000]; - int bytesRead = 0; - - line.start(); - - while (bytesRead >= 0) { - bytesRead = stream.read(abData, 0, abData.length); - // System.out.println("read data"); - if (bytesRead > 0) { - // System.out.println("about to write data"); - line.write(abData, 0, bytesRead); - // System.out.println("wrote data"); - } - } - - line.drain(); - line.close(); - - } catch (LineUnavailableException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - @Before - public void setUp() throws LineUnavailableException { - - mixer = PulseAudioMixer.getInstance(); - if (mixer.isOpen()) { - mixer.close(); - } - - mixer.open(); - - started = 0; - stopped = 0; - - } - - @Test - public void testStartAndStopEventsOnCork() - throws UnsupportedAudioFileException, IOException, - LineUnavailableException, InterruptedException { - - System.out - .println("This test checks if START and STOP notifications appear on corking"); - - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - PulseAudioSourceDataLine line; - line = (PulseAudioSourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(line); - - LineListener startStopListener = new LineListener() { - - @Override - public void update(LineEvent event) { - if (event.getType() == LineEvent.Type.START) { - System.out.println("START"); - started++; - } - - if (event.getType() == LineEvent.Type.STOP) { - System.out.println("STOP"); - stopped++; - } - } - - }; - - line.addLineListener(startStopListener); - System.out.println("Launching threadWriter"); - ThreadWriter writer = new ThreadWriter(audioInputStream, line); - writer.start(); - // System.out.println("started"); - - Thread.sleep(1000); - - // CORK - line.stop(); - - Thread.sleep(1000); - - // UNCORK - line.start(); - - Thread.sleep(1000); - - // System.out.println("waiting for thread to finish"); - writer.join(); - - Assert.assertEquals(2, started); - Assert.assertEquals(2, stopped); - - } - - @Test - public void testVolume() throws Exception { - - Mixer selectedMixer = mixer; - SourceDataLine line = (SourceDataLine) selectedMixer - .getLine(new Line.Info(SourceDataLine.class)); - - File soundFile = new File(new java.io.File(".").getCanonicalPath() - + "/testsounds/logout.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - line.open(audioFormat); - line.start(); - PulseAudioVolumeControl volume = (PulseAudioVolumeControl) line - .getControl(FloatControl.Type.VOLUME); - - volume.setValue(PulseAudioVolumeControl.MAX_VOLUME); - - byte[] abData = new byte[1000]; - int bytesRead = 0; - - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - line.write(abData, 0, bytesRead); - } - } - - line.drain(); - line.close(); - selectedMixer.close(); - - } - - @Test - public void testSettingStreamName() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - File soundFile = new File("testsounds/logout.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - PulseAudioSourceDataLine line; - line = (PulseAudioSourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - - String name = "Knights Who Say ... Oh my god, i am so sorry, i didnt mean it..."; - line.setName(name); - - line.open(audioFormat); - line.start(); - - byte[] abData = new byte[1000]; - int bytesRead = 0; - - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - line.write(abData, 0, bytesRead); - } - } - - Assert.assertTrue(line.getName() == name); - /* - * FIXME test that PulseAudio also knows this correctly using - * introspection - */ - - line.drain(); - line.stop(); - line.close(); - - } - - @Test - public void messWithStreams() throws LineUnavailableException { - System.out - .println("This test tries to unCork a stream which hasnt been corked"); - - PulseAudioSourceDataLine line = (PulseAudioSourceDataLine) mixer - .getLine(new DataLine.Info(SourceDataLine.class, - aSupportedFormat, 1000)); - - line.open(); - line.start(); - Stream s = line.getStream(); - Operation o; - synchronized (EventLoop.getEventLoop().threadLock) { - o = s.unCork(); - } - o.waitForCompletion(); - o.releaseReference(); - line.stop(); - line.close(); - } - - @After - public void tearDown() { - - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLineTest.java --- a/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLineTest.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1406 +0,0 @@ -/* PulseSourceDataLineTest.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.io.File; -import java.io.IOException; -import java.net.UnknownHostException; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.BooleanControl; -import javax.sound.sampled.Control; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.FloatControl; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; -import javax.sound.sampled.SourceDataLine; -import javax.sound.sampled.UnsupportedAudioFileException; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -public class PulseAudioSourceDataLineTest { - Mixer mixer; - SourceDataLine sourceDataLine; - private int listenerCalled = 0; - - int started = 0; - int stopped = 0; - int opened = 0; - int closed = 0; - - AudioFormat aSupportedFormat = new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 1, 1, 44100f, true); - - class ThreadWriter extends Thread { - SourceDataLine line; - AudioInputStream stream; - - public ThreadWriter(AudioInputStream stream, SourceDataLine line) - throws LineUnavailableException { - - this.line = line; - this.stream = stream; - - if (line.isOpen()) { - line.close(); - } - - } - - @Override - public void run() { - try { - AudioFormat audioFormat = stream.getFormat(); - - line.open(audioFormat); - - byte[] abData = new byte[1000]; - int bytesRead = 0; - - line.start(); - - while (bytesRead >= 0) { - bytesRead = stream.read(abData, 0, abData.length); - // System.out.println("read data"); - if (bytesRead > 0) { - // System.out.println("about to write data"); - line.write(abData, 0, bytesRead); - // System.out.println("wrote data"); - } - } - - line.drain(); - line.close(); - - } catch (LineUnavailableException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - @Before - public void setUp() throws Exception { - Mixer.Info mixerInfos[] = AudioSystem.getMixerInfo(); - Mixer.Info selectedMixerInfo = null; - // int i = 0; - for (Mixer.Info info : mixerInfos) { - // System.out.println("Mixer Line " + i++ + ": " + info.getName() + - // " " + info.getDescription()); - if (info.getName().contains("PulseAudio")) { - selectedMixerInfo = info; - } - } - Assert.assertNotNull(selectedMixerInfo); - mixer = AudioSystem.getMixer(selectedMixerInfo); - Assert.assertNotNull(mixer); - if (mixer.isOpen()) { - mixer.close(); - } - - mixer.open(); - - sourceDataLine = null; - - started = 0; - stopped = 0; - opened = 0; - closed = 0; - listenerCalled = 0; - } - - @Test - public void testOpenAndClose() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - - sourceDataLine.open(); - Assert.assertTrue(sourceDataLine.isOpen()); - - sourceDataLine.close(); - Assert.assertFalse(sourceDataLine.isOpen()); - - } - - @Test - public void testIsActiveAndIsOpen() throws LineUnavailableException { - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, aSupportedFormat, 1000)); - - Assert.assertFalse(sourceDataLine.isActive()); - Assert.assertFalse(sourceDataLine.isOpen()); - sourceDataLine.open(); - Assert.assertTrue(sourceDataLine.isOpen()); - Assert.assertFalse(sourceDataLine.isActive()); - sourceDataLine.start(); - Assert.assertTrue(sourceDataLine.isOpen()); - Assert.assertTrue(sourceDataLine.isActive()); - sourceDataLine.stop(); - Assert.assertTrue(sourceDataLine.isOpen()); - Assert.assertFalse(sourceDataLine.isActive()); - sourceDataLine.close(); - Assert.assertFalse(sourceDataLine.isOpen()); - Assert.assertFalse(sourceDataLine.isActive()); - - } - - @Test - public void testPlay() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - System.out.println("This test plays a file"); - - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - - sourceDataLine.open(audioFormat); - System.out.println("opened"); - sourceDataLine.start(); - System.out.println("started"); - byte[] abData = new byte[1000]; - int bytesRead = 0; - - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - } - } - System.out.println("done"); - - sourceDataLine.drain(); - System.out.println("drained"); - sourceDataLine.stop(); - sourceDataLine.close(); - System.out.println("closed"); - - } - - @Test(expected = IllegalArgumentException.class) - public void testWriteIntegralNumberFrames() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - - /* try writing an non-integral number of frames size */ - sourceDataLine.open(); - int frameSize = sourceDataLine.getFormat().getFrameSize(); - byte[] buffer = new byte[(frameSize * 2) - 1]; - sourceDataLine.write(buffer, 0, buffer.length); - } - - @Test(expected = IllegalArgumentException.class) - public void testWriteNegativeLength() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - - sourceDataLine.open(); - int frameSize = sourceDataLine.getFormat().getFrameSize(); - byte[] buffer = new byte[(frameSize * 2)]; - /* try writing a negative length */ - sourceDataLine.write(buffer, 0, -2); - } - - @Test(expected = ArrayIndexOutOfBoundsException.class) - public void testWriteNegativeOffset() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - - sourceDataLine.open(); - int frameSize = sourceDataLine.getFormat().getFrameSize(); - byte[] buffer = new byte[(frameSize * 2)]; - /* try writing with a negative offset */ - sourceDataLine.write(buffer, -1, buffer.length); - } - - @Test(expected = ArrayIndexOutOfBoundsException.class) - public void testWriteMoreThanArrayLength() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - - sourceDataLine.open(); - int frameSize = sourceDataLine.getFormat().getFrameSize(); - byte[] buffer = new byte[(frameSize * 2)]; - /* try writing more than the array length */ - sourceDataLine.write(buffer, 0, frameSize * 3); - } - - @Test(expected = ArrayIndexOutOfBoundsException.class) - public void testWriteMoreThanArrayLength2() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - - sourceDataLine.open(); - int frameSize = sourceDataLine.getFormat().getFrameSize(); - byte[] buffer = new byte[(frameSize * 2)]; - /* try writing more than the array length */ - sourceDataLine.write(buffer, 1, buffer.length); - } - - // FIXME - @Test - public void testWriteWithoutStart() throws UnsupportedAudioFileException, - IOException, LineUnavailableException, InterruptedException { - - System.out - .println("This test doesnt play a file; you shouldnt hear anything"); - - File soundFile = new File("testsounds/startup.wav"); - final AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - final AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - - Thread writer = new Thread() { - @Override - public void run() { - try { - sourceDataLine.open(audioFormat); - byte[] abData = new byte[1000]; - int bytesRead = 0; - int total = 0; - - while (bytesRead >= 0 && total < 50) { - - bytesRead = audioInputStream.read(abData, 0, - abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - } - - // when the line is closed (in tearDown), - // break out of the loop - if (!sourceDataLine.isOpen()) { - break; - } - total++; - } - } catch (LineUnavailableException e) { - Assert.fail(); - } catch (IOException e) { - Assert.fail(); - } - } - - }; - - writer.start(); - - Thread.sleep(100); - - writer.join(2000); - - /* assert that the writer is still waiting in write */ - Assert.assertTrue(writer.isAlive()); - - } - - @Test - public void testWriteAndClose() throws UnsupportedAudioFileException, - IOException, LineUnavailableException, InterruptedException { - System.out.println("This test tires to close the line during a write"); - - File soundFile = new File("testsounds/startup.wav"); - final AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - - sourceDataLine.open(audioFormat); - sourceDataLine.start(); - - Thread writer = new Thread() { - - @Override - public void run() { - try { - final byte[] abData = new byte[10000000]; - - int bytesRead = 0; - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, - abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - } - } - } catch (UnknownHostException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - }; - - writer.start(); - Thread.sleep(100); - - sourceDataLine.close(); - - writer.join(500); - Assert.assertFalse(writer.isAlive()); - - } - - @Test - public void testWriteAndStop() throws UnsupportedAudioFileException, - IOException, LineUnavailableException, InterruptedException { - System.out.println("This test tires to stop the line during a write"); - - File soundFile = new File("testsounds/startup.wav"); - final AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - - sourceDataLine.open(audioFormat); - sourceDataLine.start(); - - Thread writer = new Thread() { - - @Override - public void run() { - try { - final byte[] abData = new byte[10000000]; - - int bytesRead = 0; - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, - abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - } - } - } catch (UnknownHostException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - }; - - writer.start(); - - Thread.sleep(500); - - sourceDataLine.stop(); - - writer.join(500); - Assert.assertFalse(writer.isAlive()); - - sourceDataLine.close(); - - } - - @Test - public void testWriteAndFlush() throws UnsupportedAudioFileException, - IOException, LineUnavailableException, InterruptedException { - - System.out.println("This test tries to flush a line during a write"); - - File soundFile = new File("testsounds/startup.wav"); - final AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - - sourceDataLine.open(audioFormat); - sourceDataLine.start(); - - Thread writer = new Thread() { - - @Override - public void run() { - try { - final byte[] abData = new byte[10000000]; - - int bytesRead = 0; - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, - abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - } - } - } catch (UnknownHostException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - }; - - writer.start(); - - Thread.sleep(100); - - sourceDataLine.flush(); - - writer.join(500); - Assert.assertFalse(writer.isAlive()); - - sourceDataLine.stop(); - sourceDataLine.close(); - } - - @Test - public void testStartedStopped() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - - System.out - .println("This test check START/STOP events. You should see 1 START and 1 STOP event"); - - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - - sourceDataLine.open(audioFormat); - - LineListener startStopListener = new LineListener() { - - @Override - public void update(LineEvent event) { - if (event.getType() == LineEvent.Type.START) { - System.out.println("START"); - started++; - Assert.assertEquals(1, started); - } - - if (event.getType() == LineEvent.Type.STOP) { - System.out.println("STOP"); - stopped++; - Assert.assertEquals(1, stopped); - } - } - - }; - - sourceDataLine.addLineListener(startStopListener); - - byte[] abData = new byte[1000]; - int bytesRead = 0; - - sourceDataLine.start(); - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - } - } - sourceDataLine.drain(); - - sourceDataLine.stop(); - sourceDataLine.close(); - - Assert.assertEquals(1, started); - Assert.assertEquals(1, stopped); - - } - - @Test - public void test2StartAndStopEvents() throws UnsupportedAudioFileException, - IOException, LineUnavailableException, InterruptedException { - - System.out - .println("This test checks if START and STOP notifications appear on corking"); - - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - - LineListener startStopListener = new LineListener() { - - @Override - public void update(LineEvent event) { - if (event.getType() == LineEvent.Type.START) { - System.out.println("START"); - started++; - } - - if (event.getType() == LineEvent.Type.STOP) { - System.out.println("STOP"); - stopped++; - } - } - - }; - - sourceDataLine.addLineListener(startStopListener); - System.out.println("Launching threadWriter"); - ThreadWriter writer = new ThreadWriter(audioInputStream, sourceDataLine); - writer.start(); - // System.out.println("started"); - - Thread.sleep(1000); - - sourceDataLine.stop(); - - System.out.println("corked"); - - Thread.sleep(5000); - - // UNCORK - - sourceDataLine.start(); - - Thread.sleep(2000); - - // System.out.println("waiting for thread to finish"); - writer.join(); - - Assert.assertEquals(2, started); - Assert.assertEquals(2, stopped); - - } - - @Test - public void test3StartAndStopEvents() throws UnsupportedAudioFileException, - IOException, LineUnavailableException, InterruptedException { - - System.out - .println("This test checks if START and STOP notifications appear on corking"); - - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - - LineListener startStopListener = new LineListener() { - - @Override - public void update(LineEvent event) { - if (event.getType() == LineEvent.Type.START) { - System.out.println("START"); - started++; - } - - if (event.getType() == LineEvent.Type.STOP) { - System.out.println("STOP"); - stopped++; - } - } - - }; - - sourceDataLine.addLineListener(startStopListener); - System.out.println("Launching threadWriter"); - ThreadWriter writer = new ThreadWriter(audioInputStream, sourceDataLine); - writer.start(); - // System.out.println("started"); - - Thread.sleep(1000); - - sourceDataLine.stop(); - - Thread.sleep(1000); - - sourceDataLine.start(); - - Thread.sleep(1000); - - sourceDataLine.stop(); - - Thread.sleep(1000); - - sourceDataLine.start(); - - Thread.sleep(1000); - - // System.out.println("waiting for thread to finish"); - writer.join(); - - Assert.assertEquals(3, started); - Assert.assertEquals(3, stopped); - - } - - @Test(expected = IllegalStateException.class) - public void testStartOnClosedLine() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - Assert.assertNotNull(sourceDataLine); - - sourceDataLine.start(); - - } - - @Test(expected = IllegalStateException.class) - public void testStopOnClosedLine() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - Assert.assertNotNull(sourceDataLine); - - sourceDataLine.stop(); - } - - @Test(expected = IllegalArgumentException.class) - public void testPlayLessThanFrameSize() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - // the audio file must have an even number of channels - Assert.assertTrue(audioFormat.getChannels() % 2 == 0); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - - byte[] data = new byte[1]; - data[0] = (byte) 'a'; - - sourceDataLine.open(); - sourceDataLine.start(); - try { - sourceDataLine.write(data, 0, 1); - } finally { - sourceDataLine.stop(); - sourceDataLine.close(); - } - } - - @Test - public void testOpenFormat() throws LineUnavailableException, - UnsupportedAudioFileException, IOException { - /* - * This test makes sure that the default format of a line using open() - * is the same format that was passed to the mixer's getLine() function - * to get the line in the first place - */ - - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - sourceDataLine.open(); - Assert.assertTrue(sourceDataLine.getFormat().matches(audioFormat)); - sourceDataLine.close(); - } - - @Test - public void testFindLineWithFormat() throws LineUnavailableException { - System.out - .println("This test tries to find a line with a valid format"); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, aSupportedFormat)); - sourceDataLine.open(); - System.out.println(sourceDataLine.getFormat()); - sourceDataLine.close(); - - } - - @Test(expected = IllegalArgumentException.class) - public void testFindLineWithWrongFormat() throws LineUnavailableException { - System.out - .println("This test tries to acquire a line with incorrect format spec"); - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100, 10000, 1, 13, - 10, true))); - sourceDataLine.open(); - sourceDataLine.close(); - } - - @Test - public void testFindControl() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - sourceDataLine.open(); - Control[] controls = sourceDataLine.getControls(); - Assert.assertNotNull(controls); - Assert.assertTrue(sourceDataLine.getControls().length > 0); - for (Control control : controls) { - Assert.assertNotNull(control); - } - sourceDataLine.close(); - } - - @Test - public void testSupportedControls() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - sourceDataLine.open(); - Assert.assertTrue(sourceDataLine - .isControlSupported(FloatControl.Type.VOLUME)); - sourceDataLine.close(); - } - - @Test - public void testVolume() throws Exception { - - Mixer selectedMixer = mixer; - sourceDataLine = (SourceDataLine) selectedMixer.getLine(new Line.Info( - SourceDataLine.class)); - - File soundFile = new File(new java.io.File(".").getCanonicalPath() - + "/testsounds/logout.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine.open(audioFormat); - sourceDataLine.start(); - FloatControl volume = (FloatControl) sourceDataLine - .getControl(FloatControl.Type.VOLUME); - - volume.setValue(volume.getMaximum()); - - byte[] abData = new byte[1000]; - int bytesRead = 0; - - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - } - } - - sourceDataLine.drain(); - sourceDataLine.close(); - selectedMixer.close(); - - } - - @Test - public void testVolumeChanging() throws LineUnavailableException, - IOException, UnsupportedAudioFileException { - - Mixer selectedMixer = mixer; - - sourceDataLine = (SourceDataLine) selectedMixer.getLine(new Line.Info( - SourceDataLine.class)); - - File soundFile = new File(new java.io.File(".").getCanonicalPath() - + "/testsounds/logout.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine.open(audioFormat); - sourceDataLine.start(); - FloatControl volume = (FloatControl) sourceDataLine - .getControl(FloatControl.Type.VOLUME); - - volume.setValue(volume.getMinimum()); - - byte[] abData = new byte[1000]; - int bytesRead = 0; - - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - volume.setValue(volume.getValue() + 100); - } - } - - sourceDataLine.drain(); - sourceDataLine.close(); - selectedMixer.close(); - - } - - @Test - public void testOpenEvent() throws LineUnavailableException { - - listenerCalled = 0; - LineListener openListener = new LineListener() { - public void update(LineEvent event) { - Assert.assertTrue(event.getType() == LineEvent.Type.OPEN); - PulseAudioSourceDataLineTest.this.listenerCalled++; - } - }; - - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - sourceDataLine.addLineListener(openListener); - sourceDataLine.open(); - sourceDataLine.removeLineListener(openListener); - sourceDataLine.close(); - Assert.assertEquals(1, listenerCalled); - listenerCalled = 0; - } - - @Test - public void testCloseEvent() throws LineUnavailableException { - listenerCalled = 0; - LineListener closeListener = new LineListener() { - public void update(LineEvent event) { - Assert.assertTrue(event.getType() == LineEvent.Type.CLOSE); - PulseAudioSourceDataLineTest.this.listenerCalled++; - } - }; - - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - sourceDataLine.open(); - sourceDataLine.addLineListener(closeListener); - sourceDataLine.close(); - sourceDataLine.removeLineListener(closeListener); - Assert.assertEquals(1, listenerCalled); - listenerCalled = 0; - } - - @Test - public void testCloseEventWrongListener() throws LineUnavailableException { - listenerCalled = 0; - LineListener closeListener = new LineListener() { - public void update(LineEvent event) { - PulseAudioSourceDataLineTest.this.listenerCalled++; - } - }; - - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - - sourceDataLine.open(); - sourceDataLine.addLineListener(closeListener); - sourceDataLine.removeLineListener(closeListener); - sourceDataLine.close(); - Assert.assertEquals(0, listenerCalled); - listenerCalled = 0; - - } - - @Test - public void testFramePosition() throws UnsupportedAudioFileException, - IOException, LineUnavailableException { - File soundFile = new File("testsounds/logout.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - - sourceDataLine.open(audioFormat); - sourceDataLine.start(); - - byte[] abData = new byte[1000]; - int bytesRead = 0; - - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - } - } - - sourceDataLine.drain(); - sourceDataLine.stop(); - System.out.println("frame position: " - + sourceDataLine.getFramePosition()); - long expected = 136703; - long granularity = 100; - long pos = sourceDataLine.getFramePosition(); - Assert.assertTrue(Math.abs(expected - pos) < granularity); - sourceDataLine.close(); - } - - @Test - public void testFramePositionAfterPlayingTwice() - throws UnsupportedAudioFileException, IOException, - LineUnavailableException { - File soundFile = new File("testsounds/logout.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - - sourceDataLine.open(audioFormat); - sourceDataLine.start(); - - byte[] abData = new byte[1000]; - int bytesRead = 0; - - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - } - } - - sourceDataLine.drain(); - sourceDataLine.stop(); - - soundFile = new File("testsounds/logout.wav"); - audioInputStream = AudioSystem.getAudioInputStream(soundFile); - audioFormat = audioInputStream.getFormat(); - - sourceDataLine.start(); - - abData = new byte[1000]; - bytesRead = 0; - - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - } - } - - sourceDataLine.drain(); - sourceDataLine.stop(); - - System.out.println("frame position: " - + sourceDataLine.getFramePosition()); - long expected = 136703 * 2; - long granularity = 100; - long pos = sourceDataLine.getFramePosition(); - Assert.assertTrue(Math.abs(expected - pos) < granularity); - sourceDataLine.close(); - } - - @Test - public void testMicroSecondPosition() throws UnsupportedAudioFileException, - IOException, LineUnavailableException { - - File soundFile = new File("testsounds/logout.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat)); - Assert.assertNotNull(sourceDataLine); - - sourceDataLine.open(audioFormat); - sourceDataLine.start(); - - byte[] abData = new byte[1000]; - int bytesRead = 0; - - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - sourceDataLine.write(abData, 0, bytesRead); - } - } - - sourceDataLine.drain(); - sourceDataLine.stop(); - System.out.println("time position: " - + sourceDataLine.getMicrosecondPosition()); - long expected = 6200; - long granularity = 100; - long pos = sourceDataLine.getMicrosecondPosition(); - Assert.assertTrue(Math.abs(expected - pos) < granularity); - sourceDataLine.close(); - - } - - @Test - public void testBufferSizes() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - sourceDataLine.open(aSupportedFormat, 10000); - Assert.assertEquals(10000, sourceDataLine.getBufferSize()); - sourceDataLine.close(); - } - - @Test - public void testHasADefaultFormat() throws LineUnavailableException { - System.out.println("This test checks that a SourceDataLine has " - + " a default format, and it can be opened with" - + " that format"); - - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - - /* check that there is a default format */ - Assert.assertNotNull(sourceDataLine.getFormat()); - System.out.println(sourceDataLine.getFormat()); - - /* check that the line can be opened with the default format */ - sourceDataLine.open(); - sourceDataLine.close(); - - } - - @Test - public void testDefaultFormatWithGetLine() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, aSupportedFormat, 1000)); - Assert.assertEquals(aSupportedFormat, sourceDataLine.getFormat()); - - } - - @Test - public void testDefaultBufferSize() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, aSupportedFormat, 1000)); - Assert.assertEquals(StreamBufferAttributes.SANE_DEFAULT, sourceDataLine - .getBufferSize()); - } - - @Test - public void testDrainTwice() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, aSupportedFormat, 1000)); - - sourceDataLine.open(); - sourceDataLine.drain(); - sourceDataLine.drain(); - sourceDataLine.close(); - - } - - @Test - public void testDrainWithoutStartDataOnTheLine() - throws LineUnavailableException, UnsupportedAudioFileException, - IOException, InterruptedException { - - File soundFile = new File("testsounds/logout.wav"); - final AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat, 1000)); - Assert.assertNotNull(sourceDataLine); - sourceDataLine.open(); - int available = sourceDataLine.available(); - Assert.assertTrue(available > 1000); - - try { - final byte[] abData = new byte[2000]; - int bytesRead = 0; - - bytesRead = audioInputStream.read(abData, 0, abData.length); - Assert.assertTrue(bytesRead > 0); - sourceDataLine.write(abData, 0, bytesRead); - } catch (IOException e) { - System.out.println("Error"); - } - - Thread drainer = new Thread() { - @Override - public void run() { - sourceDataLine.drain(); - } - }; - - drainer.start(); - - drainer.join(1000); - - if (drainer.isAlive()) { - sourceDataLine.close(); - drainer.join(1000); - if (drainer.isAlive()) { - Assert - .fail("drain() does not return when the line has been closed"); - } - } else { - Assert.fail("drain() does not block when there is data on the " - + "source data line and it hasnt been started"); - } - - } - - @Test - public void testDrainWithoutStartNoDataOnTheLine() - throws LineUnavailableException, UnsupportedAudioFileException, - IOException, InterruptedException { - - File soundFile = new File("testsounds/logout.wav"); - final AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, audioFormat, 1000)); - Assert.assertNotNull(sourceDataLine); - sourceDataLine.open(); - int available = sourceDataLine.available(); - Assert.assertTrue(available > 1000); - - Thread drainer = new Thread() { - @Override - public void run() { - sourceDataLine.drain(); - } - }; - - drainer.start(); - drainer.join(1000); - - if (drainer.isAlive()) { - Assert - .fail("drain() does not return when there is no data on a line that hasn't been started"); - } - } - - @Test(expected = IllegalStateException.class) - public void testDrainWithoutOpen() throws LineUnavailableException { - - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, aSupportedFormat, 1000)); - - sourceDataLine.drain(); - - } - - @Test - public void testFlushTwice() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, aSupportedFormat, 1000)); - - sourceDataLine.open(); - sourceDataLine.flush(); - sourceDataLine.flush(); - sourceDataLine.close(); - - } - - @Test(expected = IllegalStateException.class) - public void testFlushWithoutOpen() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, aSupportedFormat, 1000)); - - sourceDataLine.flush(); - - } - - @Test - public void testFlushWithoutStart() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new DataLine.Info( - SourceDataLine.class, aSupportedFormat, 1000)); - sourceDataLine.open(); - sourceDataLine.flush(); - - } - - @Test - public void testMixerKnowsAboutOpenLines() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - - Assert.assertEquals(0, mixer.getSourceLines().length); - sourceDataLine.open(); - Assert.assertEquals(1, mixer.getSourceLines().length); - Assert.assertTrue(sourceDataLine == mixer.getSourceLines()[0]); - sourceDataLine.close(); - Assert.assertEquals(0, mixer.getSourceLines().length); - - } - - @Test - public void testMixerKnowsAboutOpen2Lines() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - - Assert.assertEquals(0, mixer.getSourceLines().length); - sourceDataLine.open(aSupportedFormat); - Assert.assertEquals(1, mixer.getSourceLines().length); - Assert.assertTrue(sourceDataLine == mixer.getSourceLines()[0]); - sourceDataLine.close(); - Assert.assertEquals(0, mixer.getSourceLines().length); - - } - - @Test - public void testMixerKnowsAboutOpen3Lines() throws LineUnavailableException { - sourceDataLine = (SourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - - Assert.assertEquals(0, mixer.getSourceLines().length); - sourceDataLine.open(aSupportedFormat, 10000); - Assert.assertEquals(1, mixer.getSourceLines().length); - Assert.assertTrue(sourceDataLine == mixer.getSourceLines()[0]); - sourceDataLine.close(); - Assert.assertEquals(0, mixer.getSourceLines().length); - - } - - @Test - public void testAllSourceLinesClosed() { - Assert.assertEquals(0, mixer.getSourceLines().length); - - } - - public static void debug(String string) { - System.out.println("DEBUG: " + string); - } - - @Ignore - @Test - public void testSynchronization() throws Exception { - Mixer.Info mixerInfos[] = AudioSystem.getMixerInfo(); - Mixer.Info selectedMixerInfo = null; - // int i = 0; - for (Mixer.Info info : mixerInfos) { - // System.out.println("Mixer Line " + i++ + ": " + info.getName() + - // " " + info.getDescription()); - if (info.getName().contains("PulseAudio")) { - selectedMixerInfo = info; - System.out.println(selectedMixerInfo); - } - } - - PulseAudioMixer mixer = (PulseAudioMixer) AudioSystem - .getMixer(selectedMixerInfo); - - mixer.open(); - - String fileName1 = "testsounds/startup.wav"; - File soundFile1 = new File(fileName1); - AudioInputStream audioInputStream1 = AudioSystem - .getAudioInputStream(soundFile1); - - PulseAudioSourceDataLine line1; - line1 = (PulseAudioSourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - line1.setName("Line 1"); - - String fileName2 = "testsounds/logout.wav"; - File soundFile = new File(fileName2); - AudioInputStream audioInputStream2 = AudioSystem - .getAudioInputStream(soundFile); - - PulseAudioSourceDataLine line2; - line2 = (PulseAudioSourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - line2.setName("Line 2"); - - ThreadWriter writer1 = new ThreadWriter(audioInputStream1, line1); - ThreadWriter writer2 = new ThreadWriter(audioInputStream2, line2); - // line2.start(); - // line1.start(); - - Line[] lines = { line1, line2 }; - mixer.synchronize(lines, true); - - // line2.stop(); - - debug("PulseAudioMixer: " + line1.getName() + " and " + line2.getName() - + " synchronized"); - writer1.start(); - writer2.start(); - - debug("PulseAudioMixer: writers started"); - line2.start(); - // line1.stop(); - // line1.start(); - debug("PulseAudioMixer: Started a line"); - - writer1.join(); - writer2.join(); - - debug("PulseAudioMixer: both lines joined"); - - line2.close(); - debug("PulseAudioMixer: " + line2.getName() + " closed"); - - line1.close(); - debug("PulseAudioMixer: " + line1.getName() + " closed"); - - mixer.close(); - debug("PulseAudioMixer: mixer closed"); - - } - - @After - public void tearDown() throws Exception { - started = 0; - stopped = 0; - - if (sourceDataLine != null && sourceDataLine.isOpen()) { - sourceDataLine.close(); - } - - if (mixer.isOpen()) { - mixer.close(); - } - - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourcePortTest.java --- a/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioSourcePortTest.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* PulseAudioSourcePortTest.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import static org.junit.Assert.assertNotNull; - -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.FloatControl; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; -import javax.sound.sampled.Port; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class PulseAudioSourcePortTest { - - Mixer mixer; - - @Before - public void setUp() throws Exception { - Mixer.Info mixerInfos[] = AudioSystem.getMixerInfo(); - Mixer.Info selectedMixerInfo = null; - // int i = 0; - for (Mixer.Info info : mixerInfos) { - // System.out.println("Mixer Line " + i++ + ": " + info.getName() + - // " " + info.getDescription()); - if (info.getName().contains("PulseAudio")) { - selectedMixerInfo = info; - } - } - assertNotNull(selectedMixerInfo); - mixer = AudioSystem.getMixer(selectedMixerInfo); - assertNotNull(mixer); - if (mixer.isOpen()) { - mixer.close(); - } - - mixer.open(); - - } - - @Test - public void testClose() throws LineUnavailableException { - Line.Info[] lineInfos = mixer.getSourceLineInfo(); - for (Line.Info info : lineInfos) { - if (info.getLineClass() == Port.class) { - System.out.println(info.toString()); - Port port = (Port) mixer.getLine(info); - port.close(); - } - } - } - - @Test - public void testControls() throws LineUnavailableException { - Line.Info[] lineInfos = mixer.getSourceLineInfo(); - for (Line.Info info : lineInfos) { - if (info.getLineClass() == Port.class) { - System.out.println(info.toString()); - Port port = (Port) mixer.getLine(info); - if (!port.isOpen()) { - port.open(); - } - FloatControl volumeControl = (FloatControl) port - .getControl(FloatControl.Type.VOLUME); - volumeControl.setValue(60000); - port.close(); - } - } - } - - @After - public void tearDown() { - if (mixer.isOpen()) { - mixer.close(); - } - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLineTest.java --- a/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLineTest.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,648 +0,0 @@ -/* PulseAudioTargetDataLineTest.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import java.io.File; -import java.io.IOException; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; -import javax.sound.sampled.TargetDataLine; -import javax.sound.sampled.UnsupportedAudioFileException; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -public class PulseAudioTargetDataLineTest { - - private Mixer mixer; - private TargetDataLine targetDataLine; - - int started = 0; - int stopped = 0; - - AudioFormat aSupportedFormat = new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 1, 1, 44100f, true); - - class ThreadReader extends Thread { - TargetDataLine line; - byte[] buffer; - - public ThreadReader(TargetDataLine line, byte[] buffer) - throws LineUnavailableException { - - this.line = line; - this.buffer = buffer; - - } - - @Override - public void run() { - int bytesRead = 0; - - bytesRead = line.read(buffer, 0, buffer.length); - // System.out.println("read data"); - - } - } - - @Before - public void setUp() throws LineUnavailableException { - Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo(); - Mixer.Info wantedMixerInfo = null; - for (Mixer.Info mixerInfo : mixerInfos) { - if (mixerInfo.getName().contains("PulseAudio")) { - wantedMixerInfo = mixerInfo; - } - } - Assert.assertNotNull(wantedMixerInfo); - mixer = AudioSystem.getMixer(wantedMixerInfo); - Assert.assertNotNull(mixer); - mixer.open(); - targetDataLine = null; - started = 0; - stopped = 0; - - } - - @Test - public void testOpenClose() throws LineUnavailableException { - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - targetDataLine.open(); - targetDataLine.close(); - } - - @Test - public void testIsActiveAndIsOpen() throws LineUnavailableException { - - TargetDataLine line = (TargetDataLine) mixer.getLine(new DataLine.Info( - TargetDataLine.class, aSupportedFormat, 1000)); - - Assert.assertFalse(line.isActive()); - Assert.assertFalse(line.isOpen()); - line.open(); - Assert.assertTrue(line.isOpen()); - Assert.assertFalse(line.isActive()); - line.start(); - Assert.assertTrue(line.isOpen()); - Assert.assertTrue(line.isActive()); - line.stop(); - Assert.assertTrue(line.isOpen()); - Assert.assertFalse(line.isActive()); - line.close(); - Assert.assertFalse(line.isOpen()); - Assert.assertFalse(line.isActive()); - - } - - @Test - public void testOpenEvents() throws LineUnavailableException { - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - - LineListener openListener = new LineListener() { - private int calledCount = 0; - - @Override - public void update(LineEvent event) { - Assert.assertEquals(LineEvent.Type.OPEN, event.getType()); - System.out.println("OPEN"); - calledCount++; - Assert.assertEquals(1, calledCount); - } - - }; - - targetDataLine.addLineListener(openListener); - targetDataLine.open(); - targetDataLine.removeLineListener(openListener); - targetDataLine.close(); - - } - - @Test - public void testOpenWithFormat() throws LineUnavailableException { - System.out.println("This test checks that open(AudioFormat) works"); - - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - targetDataLine.open(aSupportedFormat); - - } - - @Test - public void testRead() throws LineUnavailableException { - System.out.println("This test checks that read() sort of wroks"); - - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - targetDataLine.open(aSupportedFormat); - - byte[] buffer = new byte[1000]; - for (int i = 0; i < buffer.length; i++) { - buffer[i] = 0; - } - targetDataLine.start(); - - targetDataLine.read(buffer, 0, buffer.length); - Assert.assertTrue(buffer[999] != 0); - - buffer = new byte[1000]; - for (int i = 0; i < buffer.length; i++) { - buffer[i] = 0; - } - - targetDataLine.read(buffer, 0, buffer.length - 2); - Assert.assertTrue(buffer[999] == 0); - - targetDataLine.stop(); - targetDataLine.close(); - - } - - @Test(expected = IllegalArgumentException.class) - public void testReadLessThanFrameSize() throws LineUnavailableException { - System.out.println("This test checks that read() throws an exception " - + "when not reading an integral number of frames"); - - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - AudioFormat breakingFormat = new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 2, 2, 44100f, - true); - targetDataLine.open(breakingFormat); - - byte[] buffer = new byte[1000]; - for (int i = 0; i < buffer.length; i++) { - buffer[i] = 0; - } - targetDataLine.start(); - - targetDataLine.read(buffer, 0, buffer.length - 1); - - targetDataLine.stop(); - targetDataLine.close(); - - } - - @Test - public void testReadAndClose() throws LineUnavailableException, - InterruptedException { - System.out.println("This test tries to close a line while " - + "read()ing to check that read() returns"); - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - AudioFormat breakingFormat = new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 2, 2, 44100f, - true); - targetDataLine.open(breakingFormat); - targetDataLine.start(); - byte[] buffer = new byte[1000000]; - - ThreadReader reader = new ThreadReader(targetDataLine, buffer); - reader.start(); - - Thread.sleep(100); - - Assert.assertTrue(reader.isAlive()); - - targetDataLine.close(); - - reader.join(500); - - Assert.assertFalse(reader.isAlive()); - - } - - @Test - public void testReadAndStop() throws LineUnavailableException, - InterruptedException { - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - AudioFormat breakingFormat = new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 2, 2, 44100f, - true); - targetDataLine.open(breakingFormat); - targetDataLine.start(); - byte[] buffer = new byte[10000000]; - - ThreadReader reader = new ThreadReader(targetDataLine, buffer); - reader.start(); - - Thread.sleep(100); - - Assert.assertTrue(reader.isAlive()); - - targetDataLine.stop(); - - Thread.sleep(100); - - Assert.assertFalse(reader.isAlive()); - - targetDataLine.close(); - - } - - // this is kind of messed up - // drain should hang on a started data line - // but read should return - @Test - public void testReadAndDrain() throws LineUnavailableException, - InterruptedException { - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - AudioFormat breakingFormat = new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 2, 2, 44100f, - true); - targetDataLine.open(breakingFormat); - targetDataLine.start(); - byte[] buffer = new byte[10000000]; - - ThreadReader reader = new ThreadReader(targetDataLine, buffer); - reader.start(); - - Thread.sleep(100); - - Assert.assertTrue(reader.isAlive()); - - Thread drainer = new Thread() { - - @Override - public void run() { - targetDataLine.drain(); - - } - - }; - - drainer.start(); - - Thread.sleep(100); - - Assert.assertFalse(reader.isAlive()); - - targetDataLine.stop(); - - Thread.sleep(100); - Assert.assertFalse(drainer.isAlive()); - - targetDataLine.close(); - } - - @Test - public void testReadAndFlush() throws LineUnavailableException, - InterruptedException { - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - AudioFormat breakingFormat = new AudioFormat( - AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 2, 2, 44100f, - true); - targetDataLine.open(breakingFormat); - targetDataLine.start(); - byte[] buffer = new byte[10000000]; - - ThreadReader reader = new ThreadReader(targetDataLine, buffer); - reader.start(); - - Thread.sleep(100); - - Assert.assertTrue(reader.isAlive()); - - targetDataLine.flush(); - - Thread.sleep(100); - - Assert.assertFalse(reader.isAlive()); - - targetDataLine.stop(); - targetDataLine.close(); - } - - @Test - public void testDrain() throws LineUnavailableException, - InterruptedException { - System.out - .println("This test checks that drain() on a start()ed TargetDataLine hangs"); - - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - - targetDataLine.open(); - targetDataLine.start(); - - Thread th = new Thread(new Runnable() { - - @Override - public void run() { - targetDataLine.drain(); - } - - }); - - th.start(); - - th.join(5000); - - if (!th.isAlive()) { - targetDataLine.stop(); - th.join(); - targetDataLine.close(); - Assert.fail("drain() on a opened TargetDataLine should hang"); - } - } - - @Test(expected = IllegalStateException.class) - public void testDrainWihtoutOpen() throws LineUnavailableException { - System.out - .println("This test checks that drain() fails on a line not opened"); - - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - - targetDataLine.drain(); - - } - - @Test - public void testFlush() throws LineUnavailableException { - System.out.println("This test checks that flush() wroks"); - - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - targetDataLine.open(); - - byte[] buffer = new byte[1000]; - for (int i = 0; i < buffer.length; i++) { - buffer[i] = 0; - } - targetDataLine.start(); - - targetDataLine.read(buffer, 0, buffer.length); - targetDataLine.stop(); - targetDataLine.flush(); - targetDataLine.close(); - } - - @Test(expected = IllegalStateException.class) - public void testFlushWithoutOpen() throws LineUnavailableException { - System.out - .println("This test checks that flush() fails on a line not opened"); - - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - - targetDataLine.flush(); - } - - @Test - public void testCloseEvents() throws LineUnavailableException { - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - Assert.assertNotNull(targetDataLine); - - LineListener closeListener = new LineListener() { - private int calledCount = 0; - - @Override - public void update(LineEvent event) { - Assert.assertEquals(LineEvent.Type.CLOSE, event.getType()); - System.out.println("CLOSE"); - calledCount++; - Assert.assertEquals(1, calledCount); - } - - }; - - targetDataLine.open(); - targetDataLine.addLineListener(closeListener); - targetDataLine.close(); - targetDataLine.removeLineListener(closeListener); - - } - - @Test - public void testStartedStopped() throws LineUnavailableException, - UnsupportedAudioFileException, IOException, InterruptedException { - - File soundFile = new File("testsounds/startup.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - - TargetDataLine line; - line = (TargetDataLine) mixer.getLine(new DataLine.Info( - TargetDataLine.class, audioFormat)); - Assert.assertNotNull(line); - - started = 0; - stopped = 0; - - line.open(audioFormat); - - LineListener startStopListener = new LineListener() { - - @Override - public void update(LineEvent event) { - if (event.getType() == LineEvent.Type.START) { - System.out.println("START"); - started++; - Assert.assertEquals(1, started); - } - - if (event.getType() == LineEvent.Type.STOP) { - System.out.println("STOP"); - stopped++; - Assert.assertEquals(1, stopped); - } - } - - }; - - line.addLineListener(startStopListener); - - line.start(); - - Thread.sleep(100); - - line.stop(); - line.close(); - - Assert.assertEquals(1, started); - Assert.assertEquals(1, stopped); - - } - - @Test - public void testMixerKnowsAboutOpenLines() throws LineUnavailableException { - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - - int initiallyOpen = mixer.getTargetLines().length; - targetDataLine.open(); - Assert.assertEquals(initiallyOpen+1, mixer.getTargetLines().length); - targetDataLine.close(); - Assert.assertEquals(initiallyOpen, mixer.getTargetLines().length); - - } - - @Test - public void testAllTargetLinesClosed() { - Assert.assertEquals(0, mixer.getTargetLines().length); - - } - - @Test - public void testTargetLineHasNoControls() throws LineUnavailableException { - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - - targetDataLine.open(); - - Assert.assertEquals(0, targetDataLine.getControls().length); - - targetDataLine.close(); - } - - @Test - public void testFramePosition() throws LineUnavailableException { - System.out - .println("This test tests frame position for a target data line"); - - final int CHUNCKS = 100; - final int BUFFER_SIZE = 1000; - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - - targetDataLine.open(); - targetDataLine.start(); - byte[] data = new byte[BUFFER_SIZE]; - - for (int i = 0; i < CHUNCKS; i++) { - targetDataLine.read(data, 0, data.length); - } - - targetDataLine.stop(); - long pos = targetDataLine.getLongFramePosition(); - System.out.println("Frames read: " + pos); - long expected = BUFFER_SIZE * CHUNCKS - / targetDataLine.getFormat().getFrameSize(); - System.out.println("Expected: " + expected); - long granularity = 2; - Assert.assertTrue(Math.abs(expected - pos) < granularity); - targetDataLine.close(); - } - - @Test - public void testFramePositionWithStartAndStop() - throws LineUnavailableException, InterruptedException { - System.out - .println("This test tests frame position for a target data line"); - - final int CHUNCKS = 100; - final int BUFFER_SIZE = 1000; - targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( - TargetDataLine.class)); - - targetDataLine.open(); - targetDataLine.start(); - byte[] data = new byte[BUFFER_SIZE]; - - for (int i = 0; i < CHUNCKS; i++) { - if (i == CHUNCKS / 2) { - targetDataLine.stop(); - Thread.sleep(1000); - targetDataLine.start(); - } - - targetDataLine.read(data, 0, data.length); - } - - targetDataLine.stop(); - long pos = targetDataLine.getLongFramePosition(); - System.out.println("Frames read: " + pos); - long expected = BUFFER_SIZE * CHUNCKS - / targetDataLine.getFormat().getFrameSize(); - System.out.println("Expected: " + expected); - long granularity = 2; - Assert.assertTrue(Math.abs(expected - pos) < granularity); - targetDataLine.close(); - - } - - @After - public void tearDown() { - if (targetDataLine != null) { - if (targetDataLine.isActive()) { - targetDataLine.stop(); - } - - if (targetDataLine.isOpen()) { - targetDataLine.close(); - } - } - - if (mixer.isOpen()) { - mixer.close(); - } - } - -} diff -r 8f185d6f0164 -r e5d122ba61c0 pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetPortTest.java --- a/pulseaudio/unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetPortTest.java Mon Oct 03 16:35:35 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* PulseAudioTargetPortTest.java - Copyright (C) 2008 Red Hat, Inc. - -This file is part of IcedTea. - -IcedTea is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2. - -IcedTea is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with IcedTea; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. - */ - -package org.classpath.icedtea.pulseaudio; - -import static org.junit.Assert.assertNotNull; - -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.FloatControl; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.Mixer; -import javax.sound.sampled.Port; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class PulseAudioTargetPortTest { - - Mixer mixer; - - @Before - public void setUp() throws Exception { - Mixer.Info mixerInfos[] = AudioSystem.getMixerInfo(); - Mixer.Info selectedMixerInfo = null; - // int i = 0; - for (Mixer.Info info : mixerInfos) { - // System.out.println("Mixer Line " + i++ + ": " + info.getName() + - // " " + info.getDescription()); - if (info.getName().contains("PulseAudio")) { - selectedMixerInfo = info; - } - } - assertNotNull(selectedMixerInfo); - mixer = AudioSystem.getMixer(selectedMixerInfo); - assertNotNull(mixer); - if (mixer.isOpen()) { - mixer.close(); - } - - mixer.open(); - - } - - @Test - public void testClose() throws LineUnavailableException { - Line.Info[] lineInfos = mixer.getTargetLineInfo(); - for (Line.Info info : lineInfos) { - if (info.getLineClass() == Port.class) { - System.out.println(info.toString()); - Port port = (Port) mixer.getLine(info); - port.close(); - } - } - } - - @Test - public void testControls() throws LineUnavailableException { - Line.Info[] lineInfos = mixer.getTargetLineInfo(); - for (Line.Info info : lineInfos) { - if (info.getLineClass() == Port.class) { - System.out.println(info.toString()); - Port port = (Port) mixer.getLine(info); - if (!port.isOpen()) { - port.open(); - } - FloatControl volumeControl = (FloatControl) port - .getControl(FloatControl.Type.VOLUME); - volumeControl.setValue(60000); - port.close(); - } - } - } - - @After - public void tearDown() { - if (mixer.isOpen()) { - mixer.close(); - } - } - -}