Mercurial > hg > pulseaudio
changeset 41:94378da8ecd1
- files renamed/moved around
- added licenses
- moved around sound files; tests will fail
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AUTHORS Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,5 @@ +Authors + +Ioana Iivan (iivan@redhat.com) + +Omair Majid (omajid@redhat.com) \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/COPYING Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,340 @@ + 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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. + + <signature of Ty Coon>, 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.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,8 @@ +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) + + +Where it came 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. \ No newline at end of file
--- a/jar-build.jardesc Fri Aug 01 17:16:36 2008 -0400 +++ b/jar-build.jardesc Tue Aug 05 15:25:06 2008 -0400 @@ -1,16 +1,17 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <jardesc> - <jar path="/home/omajid/workspace/pulse-java.jar"/> - <options buildIfNeeded="true" compress="true" descriptionLocation="/pulse-java/jar-build.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="true" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/> + <jar path="pulseaudio-java.jar"/> + <options buildIfNeeded="true" compress="true" descriptionLocation="/pulseaudio-java/jar-build.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="true" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/> <storedRefactorings deprecationInfo="true" structuralOnly="false"/> <selectedProjects/> - <manifest generateManifest="false" manifestLocation="/pulse-java/manifest" manifestVersion="1.0" reuseManifest="true" saveManifest="true" usesManifest="true"> + <manifest generateManifest="false" manifestLocation="/pulseaudio-java/manifest" manifestVersion="1.0" reuseManifest="true" saveManifest="true" usesManifest="true"> <sealing sealJar="true"> <packagesToSeal/> <packagesToUnSeal/> </sealing> </manifest> <selectedElements exportClassFiles="true" exportJavaFiles="true" exportOutputFolder="false"> - <javaElement handleIdentifier="=pulse-java"/> + <javaElement handleIdentifier="=pulseaudio-java/unittests"/> + <javaElement handleIdentifier="=pulseaudio-java/src"/> </selectedElements> </jardesc>
--- a/lib/dummy Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -This is a dummy file to hack around git\'s inability to track empty directories
--- a/makefile Fri Aug 01 17:16:36 2008 -0400 +++ b/makefile Tue Aug 05 15:25:06 2008 -0400 @@ -1,9 +1,14 @@ + + + JAVAH=javah JAVAC=javac JAVA=java CC=gcc +PLATFORM_FLAGS=-DWITH_32BIT_PLATFORM + CFLAGS=-g LDFLAGS=-g @@ -27,54 +32,73 @@ # Shared Libraries lib/libpulse-java.so: \ - bin/org_openjdk_sound_EventLoop.o \ - bin/org_openjdk_sound_PulseAudioSourceDataLine.o \ - bin/jni-common.o -# bin/org_openjdk_sound_PulseAudioTargetDataLine.o + bin/org_classpath_icedtea_pulseaudio_EventLoop.o \ + bin/org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.o \ + bin/org_classpath_icedtea_pulseaudio_PulseAudioVolumeControl.o \ + bin/org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl.o \ + bin/jni-common.o +# bin/org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine.o \ gcc -g -shared -o $@ $^ /usr/lib/libpulse.so # Object files -bin/org_openjdk_sound_EventLoop.o: src/org_openjdk_sound_EventLoop.c src/org_openjdk_sound_EventLoop.h bin - gcc -g -DWITH_32BIT_PLATFORM -c -o $@ $< +bin/org_classpath_icedtea_pulseaudio_EventLoop.o: src/org_classpath_icedtea_pulseaudio_EventLoop.c src/org_classpath_icedtea_pulseaudio_EventLoop.h bin + gcc -g $(PLATFORM_FLAGS) -c -o $@ $< + +bin/org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.o: src/org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.c src/org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.h bin + gcc -g $(PLATFORM_FLAGS) -c -o $@ $< -bin/org_openjdk_sound_PulseAudioSourceDataLine.o: src/org_openjdk_sound_PulseAudioSourceDataLine.c src/org_openjdk_sound_PulseAudioSourceDataLine.h bin - gcc -g -DWITH_32BIT_PLATFORM -c -o $@ $< +bin/org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine.o: src/org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine.c src/org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine.h bin + gcc -g $(PLATFORM_FLAGS) -c -o $@ $< -#bin/org_openjdk_sound_PulseAudioTargetDataLine.o: src/org_openjdk_sound_PulseAudioTargetDataLine.c src/org_openjdk_sound_PulseAudioTargetDataLine.h bin -# gcc -g -DWITH_32BIT_PLATFORM -c -o $@ $< +bin/org_classpath_icedtea_pulseaudio_PulseAudioVolumeControl.o: src/org_classpath_icedtea_pulseaudio_PulseAudioVolumeControl.c src/org_classpath_icedtea_pulseaudio_PulseAudioVolumeControl.h + gcc -g $(PLATFORM_FLAGS) -c -o $@ $< + +bin/org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl.o: src/org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl.c src/org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl.h + gcc -g $(PLATFORM_FLAGS) -c -o $@ $< bin/jni-common.o: src/jni-common.c src/jni-common.h - gcc -g -DWITH_32BIT_PLATFORM -c -o $@ $< + gcc -g $(PLATFORM_FLAGS) -c -o $@ $< # Java headers -src/org_openjdk_sound_EventLoop.h: src/org/openjdk/sound/EventLoop.class - javah -d src -classpath src org.openjdk.sound.EventLoop +src/org_classpath_icedtea_pulseaudio_EventLoop.h: src/org/classpath/icedtea/pulseaudio/EventLoop.class + javah -d src -classpath src org.classpath.icedtea.pulseaudio.EventLoop + +src/org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.h: src/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.class + javah -d src -classpath src org.classpath.icedtea.pulseaudio.PulseAudioSourceDataLine -src/org_openjdk_sound_PulseAudioSourceDataLine.h: src/org/openjdk/sound/PulseAudioSourceDataLine.class - javah -d src -classpath src org.openjdk.sound.PulseAudioSourceDataLine +src/org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine.h: src/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.class + javah -d src -classpath src org.classpath.icedtea.pulseaudio.PulseAudioTargetDataLine -#src/org_openjdk_sound_PulseAudioTargetDataLine.h: src/org/openjdk/sound/PulseAudioTargetDataLine.class -# javah -d src -classpath src org.openjdk.sound.PulseAudioTargetDataLine +src/org_classpath_icedtea_pulseaudio_PulseAudioVolumeControl.h: src/org/classpath/icedtea/pulseaudio/PulseAudioVolumeControl.class + javah -d src -classpath src org.classpath.icedtea.pulseaudio.PulseAudioVolumeControl + +src/org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl.h: src/org/classpath/icedtea/pulseaudio/PulseAudioStreamVolumeControl.class + javah -d src -classpath src org.classpath.icedtea.pulseaudio.PulseAudioStreamVolumeControl # Compile Java # Actually, this is not the best thing to do; javac might do some crazy things # but we are only doing this so we can get up to date jni header files -src/org/openjdk/sound/EventLoop.class: src/org/openjdk/sound/EventLoop.java - javac -classpath src $< +.SUFFIXES: .java .class -src/org/openjdk/sound/PulseAudioSourceDataLine.class: src/org/openjdk/sound/PulseAudioSourceDataLine.java +.java.class: javac -classpath src $< -#src/org/openjdk/sound/PulseAudioTargetDataLine.class: src/org/openjdk/sound/PulseAudioTargetDataLine.java -# javac $< + +#src/org/classpath/icedtea/pulseaudio/EventLoop.class: src/org/classpath/icedtea/pulseaudio/EventLoop.java +# javac -classpath src $< # +#src/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.class: src/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java +# javac -classpath src $< -src/org/openjdk/sound/PulseAudioMixerInfo.class: src/org/openjdk/sound/PulseAudioMixerInfo.java - javac $< +#src/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.class: src/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java +# javac $< + +#src/org/classpath/icedtea/pulseaudio/PulseAudioVolumeControl.class: src/org/classpath/icedtea/pulseaudio/PulseAudioMixerInfo.java + # Build Directories
--- a/manifest Fri Aug 01 17:16:36 2008 -0400 +++ b/manifest Tue Aug 05 15:25:06 2008 -0400 @@ -1,3 +1,1 @@ Manifest-Version: 1.0 -Sealed: true -
--- a/src/META-INF/services/javax.sound.sampled.spi.MixerProvider Fri Aug 01 17:16:36 2008 -0400 +++ b/src/META-INF/services/javax.sound.sampled.spi.MixerProvider Tue Aug 05 15:25:06 2008 -0400 @@ -1,3 +1,3 @@ # Providers of sound mixers -org.openjdk.sound.PulseAudioMixerProvider +org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider
--- a/src/jni-common.c Fri Aug 01 17:16:36 2008 -0400 +++ b/src/jni-common.c Tue Aug 05 15:25:06 2008 -0400 @@ -1,3 +1,41 @@ +/* jni-common.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 "jni-common.h" #include <assert.h> @@ -7,7 +45,6 @@ */ void throwByName(JNIEnv* env, const char* name, const char* msg) { jclass cls = (*env)->FindClass(env, name); - /* if cls is NULL, an exception has already been thrown */ if (cls != NULL) { (*env)->ThrowNew(env, cls, msg); return;
--- a/src/jni-common.h Fri Aug 01 17:16:36 2008 -0400 +++ b/src/jni-common.h Tue Aug 05 15:25:06 2008 -0400 @@ -1,3 +1,41 @@ +/* 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/ContextEvent.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,56 @@ +/* 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; + +public class ContextEvent { + + public static enum Type { + UNCONNECTED, CONNECTING, AUTHORIZING, SETTING_NAME, READY, FAILED, TERMINATED + } + + private Type type; + + public ContextEvent(Type type) { + this.type = type; + } + + public Type getType() { + return type; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/ContextListener.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,44 @@ +/* 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; + +public interface ContextListener { + + public void update(ContextEvent e); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/EventLoop.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,237 @@ +/* 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.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Semaphore; + +import org.classpath.icedtea.pulseaudio.ContextEvent.Type; + +/* + * any methods that can obstruct the behaviour of pa_mainloop + * should run synchronized + * + * + */ + +public class EventLoop implements Runnable { + + /* + * the threadLock object is the object used for synchronizing the + * non-thread-safe operations of pulseaudio's c api + * + */ + public Object threadLock = new Object(); + + private List<ContextListener> contextListeners; + // private List<SourceDataLine> lines; + private String name; + private String serverString; + + private int status; + + public Semaphore finished = new Semaphore(0); + + /* + * 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(); + + private native void native_set_sink_volume(long streamPointer, int volume); + + /* + * These fields hold pointers + * + * When going from 32 bit to 64 bit, these will have to be changed to longs, + * but not otherwise + * + * Pointer sizes change from 32 bit to 64 bit, but java data types's sizes + * dont + * + */ + @SuppressWarnings("unused") + private long contextPointer; + @SuppressWarnings("unused") + private long mainloopPointer; + + /* + * + */ + + static { + try { + String library = new java.io.File(".").getCanonicalPath() + + java.io.File.separatorChar + "lib" + + java.io.File.separatorChar + + System.mapLibraryName("pulse-java"); + System.out.println(library); + System.load(library); + } catch (IOException e) { + assert ("Loading failed".endsWith("library")); + } + } + + public EventLoop() { + contextListeners = new ArrayList<ContextListener>(); + } + + public void setAppName(String name) { + this.name = name; + } + + public void setServer(String serverString) { + this.serverString = serverString; + } + + @Override + public void run() { + native_setup(this.name, this.serverString); + + /* + * 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 a funky parameter (in milliseconds) + // timout = 0 means dont block + // setting it to even 1 makes the program crawl + // question is, why? + native_iterate(0); + + if (Thread.interrupted()) { + native_shutdown(); + System.out.println(this.getClass().getName() + + ": shutting down"); + finished.release(); + return; + + } + } + } + + } + + public void addContextListener(ContextListener l) { + synchronized (threadLock) { + contextListeners.add(l); + } + } + + public int getStatus() { + return this.status; + } + + public void update(int status) { + synchronized (threadLock) { + System.out.println(this.getClass().getName() + + ".update() called! status = " + status); + this.status = status; + switch (status) { + case 0: + fireEvent(new ContextEvent(Type.UNCONNECTED)); + break; + case 1: + fireEvent(new ContextEvent(Type.CONNECTING)); + break; + case 2: + break; + case 3: + break; + case 4: + fireEvent(new ContextEvent(Type.READY)); + break; + case 5: + fireEvent(new ContextEvent(Type.FAILED)); + break; + case 6: + fireEvent(new ContextEvent(Type.TERMINATED)); + break; + default: + + } + } + } + + private void fireEvent(final ContextEvent e) { + + Thread th = new Thread(new Runnable() { + + @Override + public void run() { + synchronized (contextListeners) { + for (ContextListener listener : contextListeners) { + listener.update(e); + } + } + } + + }); + + th.start(); + + } + + public void setVolume(long streamPointer, int volume) { + + synchronized (threadLock) { + native_set_sink_volume(streamPointer, volume); + } + + } + + public long getContextPointer() { + return contextPointer; + } + + public long getMainLoopPointer() { + return mainloopPointer; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,414 @@ +/* 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.io.File; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Semaphore; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Control; +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.Control.Type; + +public class PulseAudioMixer implements javax.sound.sampled.Mixer { + // singleton + + public EventLoop eventLoop; + public Thread eventLoopThread; + + private static PulseAudioMixer _instance = null; + + private static final String DEFAULT_APP_NAME = "Java App"; + + private boolean isOpen = false; + + private List<PulseAudioSourceDataLine> sourceLines = new ArrayList<PulseAudioSourceDataLine>(); + // private List<PulseAudioTargetDataLine> targetLines = null; + + private Line.Info sourceDataLineInfo = new Line.Info( + PulseAudioSourceDataLine.class); + // private Line.Info targetDataLineInfo = new + // Line.Info(PulseAudioTargetDataLine.class); + + List<LineListener> lineListeners = null; + + private PulseAudioMixer() { + lineListeners = new ArrayList<LineListener>(); + sourceLines = new ArrayList<PulseAudioSourceDataLine>(); + // _targetLines = new ArrayList<PulseAudioTargetDataLine>(); + } + + synchronized public static PulseAudioMixer getInstance() { + if (_instance == null) { + _instance = new PulseAudioMixer(); + } + return _instance; + } + + @Override + public Line getLine(javax.sound.sampled.Line.Info info) + throws LineUnavailableException { + + if (!this.isOpen) { + throw new LineUnavailableException(); + } + + if (info.matches(sourceDataLineInfo)) { + PulseAudioSourceDataLine sourceLine = null; + sourceLine = new PulseAudioSourceDataLine(eventLoop); + sourceLines.add(sourceLine); + return sourceLine; + } + + // if (info.matches(_targetDataLineInfo)) { + // PulseAudioTargetDataLine targetLine = new PulseAudioTargetDataLine(); + // _targetLines.add(targetLine); + // return targetLine; + // } + + throw new IllegalArgumentException(); + } + + @Override + public int getMaxLines(javax.sound.sampled.Line.Info info) { + return AudioSystem.NOT_SPECIFIED; + } + + @Override + public Info getMixerInfo() { + return PulseAudioMixerInfo.getInfo(); + } + + @Override + public javax.sound.sampled.Line.Info[] getSourceLineInfo() { + Line.Info[] info = { new Line.Info(PulseAudioSourceDataLine.class), }; + return info; + } + + @Override + public javax.sound.sampled.Line.Info[] getSourceLineInfo( + javax.sound.sampled.Line.Info info) { + Line.Info sourceInfo = new Line.Info(PulseAudioSourceDataLine.class); + if (info.matches(sourceInfo)) { + Line.Info[] sourceInfos = { sourceInfo, }; + return sourceInfos; + } else { + Line.Info[] sourceInfos = {}; + return sourceInfos; + + } + } + + @Override + public Line[] getSourceLines() { + // return (Line[]) _sourceLines.toArray(); + return null; + + } + + @Override + public javax.sound.sampled.Line.Info[] getTargetLineInfo() { + Line.Info[] info = { new Line.Info(PulseAudioTargetDataLine.class), }; + return info; + } + + @Override + public javax.sound.sampled.Line.Info[] getTargetLineInfo( + javax.sound.sampled.Line.Info info) { + Line.Info sourceInfo = new Line.Info(PulseAudioTargetDataLine.class); + if (info.matches(sourceInfo)) { + Line.Info[] sourceInfos = { sourceInfo, }; + return sourceInfos; + } else { + Line.Info[] sourceInfos = {}; + return sourceInfos; + } + } + + @Override + public Line[] getTargetLines() { + // return (Line[]) _targetLines.toArray(); + return null; + } + + @Override + public boolean isLineSupported(javax.sound.sampled.Line.Info info) { + // if ( _sourceDataLineInfo.matches(info)) { + // return true; + // } + return false; + } + + @Override + public boolean isSynchronizationSupported(Line[] lines, boolean maintainSync) { + // FIXME + return false; + } + + @Override + public void synchronize(Line[] lines, boolean maintainSync) { + // FIXME pulse audio supports this + throw new IllegalArgumentException(); + } + + @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() { + + if (!this.isOpen) { + return; // TODO do we throw an exception too? + } + + eventLoopThread.interrupt(); + + try { + eventLoop.finished.acquire(); + } catch (InterruptedException e) { + System.out.println(this.getClass().getName() + + ": interrupted while waiting for eventloop to finish"); + } + + System.out.println(this.getClass().getName() + ": closing"); + + this.isOpen = false; + fireEvent(new LineEvent(this, LineEvent.Type.CLOSE, + AudioSystem.NOT_SPECIFIED)); + + /* + * FIXME need to clean up the listeners on close without a race + * condition + */ + + } + + @Override + public Control getControl(Type control) { + return null; + } + + @Override + public Control[] getControls() { + return null; + } + + @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) { + // FIXME + return false; + } + + @Override + public boolean isOpen() { + return this.isOpen; + } + + @Override + public void open() throws LineUnavailableException { + openLocal(); + } + + public void open(String appName, String host) throws UnknownHostException, + LineUnavailableException { + openRemote(appName, host); + } + + public void openLocal() throws LineUnavailableException { + openLocal(DEFAULT_APP_NAME); + } + + public void openLocal(String appName) throws LineUnavailableException { + try { + openRemote(appName, null); + } catch (UnknownHostException e) { + // not possible + } + } + + public void openRemote(String appName, String host) + throws UnknownHostException, LineUnavailableException { + openRemote(appName, host, null); + } + + synchronized public void openRemote(String appName, String host, + Integer port) throws UnknownHostException, LineUnavailableException { + if (this.isOpen) { + return; + } + + InetAddress addr = InetAddress.getAllByName(host)[0]; + + if (port != null) { + host = addr.getHostAddress(); + host = host + ":" + String.valueOf(port); + } + + eventLoop = new EventLoop(); + eventLoop.setAppName(appName); + eventLoop.setServer(host); + + final Semaphore ready = new Semaphore(0); + + eventLoop.addContextListener(new ContextListener() { + + @Override + public void update(ContextEvent e) { + System.out.println("Event detected " + e.getType().toString()); + if (e.getType() == ContextEvent.Type.READY + || e.getType() == ContextEvent.Type.FAILED + || e.getType() == ContextEvent.Type.TERMINATED) { + ready.release(); + } + } + + }); + + eventLoopThread = new Thread(eventLoop, "PulseAudio Eventloop Thread"); + + eventLoopThread.setDaemon(false); + eventLoopThread.start(); + + try { + System.out.println("waiting..."); + ready.acquire(); + if (eventLoop.getStatus() != 4) { + throw new LineUnavailableException(); + } + + System.out.println("got signal"); + } catch (InterruptedException e) { + System.out.println("got interrupted"); + } + + this.isOpen = true; + fireEvent(new LineEvent(this, LineEvent.Type.OPEN, + AudioSystem.NOT_SPECIFIED)); + + } + + @Override + synchronized public void removeLineListener(LineListener listener) { + lineListeners.remove(listener); + } + + synchronized private void fireEvent(final LineEvent e) { + Thread th = new Thread(new Runnable() { + @Override + public void run() { + synchronized (lineListeners) { + for (LineListener lineListener : lineListeners) { + lineListener.update(e); + } + } + } + }); + th.start(); + } + + public static void main(String[] args) 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 selectedMixer = (PulseAudioMixer) AudioSystem + .getMixer(selectedMixerInfo); + + selectedMixer.open(); + SourceDataLine line = (SourceDataLine) selectedMixer + .getLine(new Line.Info(PulseAudioSourceDataLine.class)); + + System.out.println("got a line"); + + File soundFile = new File("new.wav"); + AudioInputStream audioInputStream = AudioSystem + .getAudioInputStream(soundFile); + AudioFormat audioFormat = audioInputStream.getFormat(); + 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); + } + } + + System.out.println("about to close"); + line.flush(); + selectedMixer.close(); + + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/PulseAudioMixerInfo.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,63 @@ +/* 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 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", "openjdk", + "the ear-candy mixer", "0.01"); + } + + return _instance; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/PulseAudioMixerProvider.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,63 @@ +/* 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; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,389 @@ +/* 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.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Semaphore; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.Control; +import javax.sound.sampled.Line; +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.Control.Type; + +public class PulseAudioSourceDataLine implements SourceDataLine { + + private static final int DEFAULT_BUFFER_SIZE = 1000; + private String streamName = "Java Stream"; + private List<StreamListener> streamListeners = new ArrayList<StreamListener>(); + + private EventLoop eventLoop = null; + + private boolean isOpen = false; + private boolean isPaused = false; + + private AudioFormat format = null; + + private List<LineListener> listeners; + + /* + * When moving from 32bit platform to 64 bit platform, these variables + * should make life fun + * + */ + @SuppressWarnings("unused") + private long streamPointer; + + private native void native_open(long contextPointer, String name, + String encoding, float rate, int size, int channels, + boolean bigEndian, int bufferSize); + + private native void native_write(byte[] data, int offset, int length); + + private native int native_get_writable_size(); + + private native int native_getOperationState(int operationState); + + private native int native_flush(); + + private native void native_start(); + + private native void native_pause(); + + private native void native_resume(); + + private native int native_drain(); + + private native void native_close(); + + static { + try { + String library = new java.io.File(".").getCanonicalPath() + + java.io.File.separatorChar + "lib" + + java.io.File.separatorChar + + System.mapLibraryName("pulse-java"); + System.out.println(library); + System.load(library); + } catch (IOException e) { + assert ("Loading failed".endsWith("library")); + } + } + + public PulseAudioSourceDataLine(EventLoop eventLoop) { + this.eventLoop = eventLoop; + this.listeners = new ArrayList<LineListener>(); + } + + public void open(AudioFormat format, int bufferSize) + throws LineUnavailableException { + if (isOpen) { + throw new IllegalStateException("Line is already open"); + } + + isOpen = true; + + int channels = format.getChannels(); + float rate = format.getSampleRate(); + int sampleSize = format.getSampleSizeInBits(); + String encoding = format.getEncoding().toString(); + boolean bigEndian = format.isBigEndian(); + + synchronized (eventLoop.threadLock) { + native_open(eventLoop.getContextPointer(), streamName, encoding, + rate, sampleSize, channels, bigEndian, bufferSize); + } + } + + public void open(AudioFormat format) throws LineUnavailableException { + open(format, DEFAULT_BUFFER_SIZE); + + } + + public void open() throws LineUnavailableException { + format = new AudioFormat(44100, 16, 2, true, false); + open(format, DEFAULT_BUFFER_SIZE); + } + + @Override + public int write(byte[] data, int offset, int length) { + + int position = offset; + int remainingLength = length; + int availableSize; + + int sizeWritten = 0; + + while (remainingLength != 0) { + + synchronized (eventLoop.threadLock) { + availableSize = native_get_writable_size(); + if (availableSize < 0) { + return sizeWritten; + } + if (availableSize > remainingLength) { + availableSize = remainingLength; + } + /* write a little bit of the buffer */ + native_write(data, position, availableSize); + + sizeWritten += availableSize; + position += availableSize; + remainingLength -= availableSize; + + } + } + + // all the data should have been played by now + assert (sizeWritten == length); + + /* + * FIXME when the stream is flushed() etc, instead of returning length + * this should unblock and return the the size of data written so far + */ + return sizeWritten; + } + + public void start() { + if (isPaused) { + native_resume(); + isPaused = false; + return; + } else { + final Semaphore semaphore = new Semaphore(0); + + synchronized (eventLoop.threadLock) { + + this.addStreamListener(new StreamListener() { + @Override + public void update(StreamEvent e) { + System.out.println(this.getClass().getName() + + " waiting to stream to become ready"); + if (e.getType() == StreamEvent.Type.READY) { + semaphore.release(); + } + } + }); + + System.out.println("about to open stream"); + native_start(); + } + + try { + semaphore.acquire(); + } catch (InterruptedException e) { + // throw new LineUnavailableException("unable to prepare + // stream"); + } + System.out.println(this.getClass().getName() + "stream is ready"); + } + + /* + * for(LineListener l :listeners) { l.update(new LineEvent(this, + * LineEvent.Type.START, 0)); } + */ + } + + public void stop() { + synchronized (eventLoop.threadLock) { + native_pause(); + } + isPaused = true; + + } + + public void addLineListener(LineListener listener) { + this.listeners.add(listener); + } + + public void removeLineListener(LineListener listener) { + this.listeners.remove(listener); + } + + private void addStreamListener(StreamListener listener) { + this.streamListeners.add(listener); + } + + public boolean isOpen() { + return isOpen; + } + + public int available() { + synchronized (eventLoop.threadLock) { + return native_get_writable_size(); + } + }; + + public void close() { + synchronized (eventLoop.threadLock) { + native_close(); + } + + for (LineListener l : this.listeners) { + l.update(new LineEvent(this, LineEvent.Type.CLOSE, 0)); + } + + } + + public int getBufferSize() { + // TODO Auto-generated method stub + return 0; + } + + public AudioFormat getFormat() { + // TODO Auto-generated method stub + return null; + } + + public int getFramePosition() { + // TODO Auto-generated method stub + return 0; + } + + public float getLevel() { + // TODO Auto-generated method stub + return 0; + } + + public long getLongFramePosition() { + // TODO Auto-generated method stub + return 0; + } + + public long getMicrosecondPosition() { + // TODO Auto-generated method stub + return 0; + } + + public boolean isActive() { + // TODO Auto-generated method stub + return false; + } + + public boolean isRunning() { + // TODO Auto-generated method stub + return false; + } + + public Control getControl(Type control) { + return null; + } + + public Control[] getControls() { + // TODO Auto-generated method stub + return null; + } + + public javax.sound.sampled.Line.Info getLineInfo() { + return new Line.Info(SourceDataLine.class); + } + + public boolean isControlSupported(Type control) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void drain() { + int operationPointer; + int operationState; + synchronized (eventLoop.threadLock) { + operationPointer = native_drain(); + operationState = native_getOperationState(operationPointer); + } + while (operationState != 1) { + synchronized (eventLoop.threadLock) { + operationState = native_getOperationState(operationPointer); + } + } + + } + + @Override + public void flush() { + int operationPointer; + int operationState; + synchronized (eventLoop.threadLock) { + operationPointer = native_flush(); + operationState = native_getOperationState(operationPointer); + } + while (operationState != 1) { + synchronized (eventLoop.threadLock) { + operationState = native_getOperationState(operationPointer); + } + } + + } + + public void update(int status) { + synchronized (eventLoop.threadLock) { + System.out.println(this.getClass().getCanonicalName() + + ".update() called! status = " + status); + switch (status) { + case 0: + fireEvent(new StreamEvent(StreamEvent.Type.UNCONNECTED)); + break; + case 1: + fireEvent(new StreamEvent(StreamEvent.Type.CREATING)); + break; + case 2: + fireEvent(new StreamEvent(StreamEvent.Type.READY)); + break; + case 3: + fireEvent(new StreamEvent(StreamEvent.Type.FAILED)); + break; + case 4: + break; + default: + assert ("not supposed to happen".indexOf("false") >= 0); + } + } + } + + private void fireEvent(StreamEvent e) { + + for (StreamListener streamListener : streamListeners) { + streamListener.update(e); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/PulseAudioStreamVolumeControl.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,113 @@ +/* PulseAudioStreamVolumeControl.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.FloatControl; + +public class PulseAudioStreamVolumeControl extends FloatControl { + + private FloatControl.Type type; + + static { + try { + String library = new java.io.File(".").getCanonicalPath() + + java.io.File.separatorChar + "lib" + + java.io.File.separatorChar + + System.mapLibraryName("pulse-java"); + System.out.println(library); + System.load(library); + } catch (IOException e) { + assert ("Loading failed".endsWith("library")); + } + } + + @SuppressWarnings("unused") + private long streamPointer; + @SuppressWarnings("unused") + private long mainLoopPointer; + + protected PulseAudioStreamVolumeControl(Type type, float minimum, + float maximum, float precision, int updatePeriod, + float initialValue, String units, long streamPointer, + long mainLoopPointer) { + super(type, minimum, maximum, precision, updatePeriod, initialValue, + units); + assert (type.equals(Type.VOLUME)); + this.streamPointer = streamPointer; + this.mainLoopPointer = mainLoopPointer; + + } + + @Override + public float getMaximum() { + // TODO Auto-generated method stub + return super.getMaximum(); + } + + @Override + public float getMinimum() { + // TODO Auto-generated method stub + return super.getMinimum(); + } + + @Override + public Type getType() { + // TODO Auto-generated method stub + return type; + } + + @Override + public String getUnits() { + // TODO Auto-generated method stub + return super.getUnits(); + } + + public native float getValue(); + + public native void setValue(float newValue); + + @Override + public void shift(float from, float to, int microseconds) { + // TODO Auto-generated method stub + super.shift(from, to, microseconds); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,225 @@ +/* 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 java.io.IOException; +import java.util.ArrayList; + +import javax.sound.sampled.*; +import javax.sound.sampled.Control.Type; + +public class PulseAudioTargetDataLine implements TargetDataLine { + + protected long contextPointer; + protected long mainLoopPointer; + protected long streamPointer; + protected boolean isOpen = false; + protected boolean isPaused = false; + protected int defaultBufferSize; + protected ArrayList<LineListener> listeners; + + static { + try { + String library = new java.io.File(".").getCanonicalPath() + + java.io.File.separatorChar + "lib" + + java.io.File.separatorChar + + System.mapLibraryName("pulse-java"); + System.out.println(library); + System.load(library); + } catch (IOException e) { + assert ("Loading failed".endsWith("library")); + } + } + + public void open(AudioFormat format, int bufferSize) + throws LineUnavailableException { + isOpen = true; + + int channels = format.getChannels(); + float rate = format.getSampleRate(); + int sampleSize = format.getSampleSizeInBits(); + String encoding = format.getEncoding().toString(); + boolean bigEndian = format.isBigEndian(); + openStream(encoding, rate, sampleSize, channels, bigEndian, bufferSize); + } + + public void open(AudioFormat format) throws LineUnavailableException { + open(format, defaultBufferSize); + + } + + public void open() throws LineUnavailableException { + openStream("PCM_SIGNED", 44100, 16, 2, false, defaultBufferSize); + } + + private native void openStream(String encoding, float rate, int size, + int channels, boolean bigEndian, int bufferSize); + + static { + System.loadLibrary("PulseAudioSourceDataLine"); + } + + @Override + public int read(byte[] b, int off, int len) { + readFromStream(b, off, len); + return len; + } + + private native void readFromStream(byte[] b, int off, int len); + + public void start() { + if (isPaused) { + resumeStream(); + isPaused = false; + } else { + startStream(); + } + + for (LineListener l : listeners) { + l.update(new LineEvent(this, LineEvent.Type.START, 0)); + } + } + + public void stop() { + pauseStream(); + isPaused = true; + + } + + private native void startStream(); + + private native void pauseStream(); + + private native void resumeStream(); + + @Override + public void drain() { + // TODO Auto-generated method stub + + } + + @Override + public void flush() { + // TODO Auto-generated method stub + + } + + public void addLineListener(LineListener listener) { + listeners.add(listener); + } + + public void removeLineListener(LineListener listener) { + listeners.remove(listener); + } + + public boolean isOpen() { + return isOpen; + } + + public native int available(); + + public void close() { + closeStream(); + for (LineListener l : listeners) { + l.update(new LineEvent(this, LineEvent.Type.CLOSE, 0)); + } + + } + + private native void closeStream(); + + public int getBufferSize() { + // TODO Auto-generated method stub + return 0; + } + + public AudioFormat getFormat() { + // TODO Auto-generated method stub + return null; + } + + public int getFramePosition() { + // TODO Auto-generated method stub + return 0; + } + + public float getLevel() { + // TODO Auto-generated method stub + return 0; + } + + public long getLongFramePosition() { + // TODO Auto-generated method stub + return 0; + } + + public long getMicrosecondPosition() { + // TODO Auto-generated method stub + return 0; + } + + public boolean isActive() { + // TODO Auto-generated method stub + return false; + } + + public boolean isRunning() { + // TODO Auto-generated method stub + return false; + } + + public Control getControl(Type control) { + // TODO Auto-generated method stub + return null; + } + + public Control[] getControls() { + // TODO Auto-generated method stub + return null; + } + + public javax.sound.sampled.Line.Info getLineInfo() { + return new Line.Info(SourceDataLine.class); + } + + public boolean isControlSupported(Type control) { + // TODO Auto-generated method stub + return false; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/PulseAudioVolumeControl.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,51 @@ +/* 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; + +public class PulseAudioVolumeControl extends FloatControl { + + protected PulseAudioVolumeControl(Type type, float minimum, float maximum, + float precision, int updatePeriod, float initialValue, String units) { + super(type, minimum, maximum, precision, updatePeriod, initialValue, + units); + + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/StreamEvent.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,58 @@ +/* StreamEvent.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; + +public class StreamEvent { + + public static enum Type { + UNCONNECTED, CREATING, READY, FAILED, TERMINATED, + } + + + private Type type; + + public StreamEvent(StreamEvent.Type type) { + this.type = type; + } + + public Type getType() { + return this.type; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/classpath/icedtea/pulseaudio/StreamListener.java Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,47 @@ +/* StreamListener.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; + + +public interface StreamListener{ + + public void update(StreamEvent e); + +} +
--- a/src/org/openjdk/sound/ContextEvent.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -package org.openjdk.sound; - -public class ContextEvent { - - public static enum Type { - UNCONNECTED, CONNECTING, AUTHORIZING, SETTING_NAME, READY, FAILED, TERMINATED - } - - private Type type; - - public ContextEvent(Type type) { - this.type = type; - } - - public Type getType() { - return type; - } - -}
--- a/src/org/openjdk/sound/ContextListener.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -package org.openjdk.sound; - -public interface ContextListener { - - public void update(ContextEvent e); - -}
--- a/src/org/openjdk/sound/EventLoop.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -package org.openjdk.sound; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Semaphore; - -import org.openjdk.sound.ContextEvent.Type; - -/* - * any methods that can obstruct the behaviour of pa_mainloop - * should run synchronized - * - * - */ - -public class EventLoop implements Runnable { - - /* - * the threadLock object is the object used for synchronizing the - * non-thread-safe operations of pulseaudio's c api - * - */ - public Object threadLock = new Object(); - - private List<ContextListener> contextListeners; - // private List<SourceDataLine> lines; - private String name; - private String serverString; - - private int status; - - public Semaphore finished = new Semaphore(0); - - /* - * 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(); - - private native void native_set_sink_volume(long streamPointer, int volume); - - /* - * These fields hold pointers - * - * When going from 32 bit to 64 bit, these will have to be changed to longs, - * but not otherwise - * - * Pointer sizes change from 32 bit to 64 bit, but java data types's sizes - * dont - * - */ - @SuppressWarnings("unused") - private long contextPointer; - @SuppressWarnings("unused") - private long mainloopPointer; - - /* - * - */ - - static { - try { - String library = new java.io.File(".").getCanonicalPath() - + java.io.File.separatorChar + "lib" - + java.io.File.separatorChar - + System.mapLibraryName("pulse-java"); - System.out.println(library); - System.load(library); - } catch (IOException e) { - assert ("Loading failed".endsWith("library")); - } - } - - public EventLoop() { - contextListeners = new ArrayList<ContextListener>(); - } - - public void setAppName(String name) { - this.name = name; - } - - public void setServer(String serverString) { - this.serverString = serverString; - } - - @Override - public void run() { - native_setup(this.name, this.serverString); - - /* - * 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 a funky parameter (in milliseconds) - // timout = 0 means dont block - // setting it to even 1 makes the program crawl - // question is, why? - native_iterate(0); - - if (Thread.interrupted()) { - native_shutdown(); - System.out.println(this.getClass().getName() - + ": shutting down"); - finished.release(); - return; - - } - } - } - - } - - public void addContextListener(ContextListener l) { - synchronized (threadLock) { - contextListeners.add(l); - } - } - - public int getStatus() { - return this.status; - } - - public void update(int status) { - synchronized (threadLock) { - System.out.println(this.getClass().getName() - + ".update() called! status = " + status); - this.status = status; - switch (status) { - case 0: - fireEvent(new ContextEvent(Type.UNCONNECTED)); - break; - case 1: - fireEvent(new ContextEvent(Type.CONNECTING)); - break; - case 2: - break; - case 3: - break; - case 4: - fireEvent(new ContextEvent(Type.READY)); - break; - case 5: - fireEvent(new ContextEvent(Type.FAILED)); - break; - case 6: - fireEvent(new ContextEvent(Type.TERMINATED)); - break; - default: - - } - } - } - - private void fireEvent(final ContextEvent e) { - - Thread th = new Thread(new Runnable() { - - @Override - public void run() { - synchronized (contextListeners) { - for (ContextListener listener : contextListeners) { - listener.update(e); - } - } - } - - }); - - th.start(); - - } - - public void setVolume(long streamPointer, int volume) { - - synchronized (threadLock) { - native_set_sink_volume(streamPointer, volume); - } - - } - - public long getContextPointer() { - return contextPointer; - } - - public long getMainLoopPointer() { - return mainloopPointer; - } - -}
--- a/src/org/openjdk/sound/PulseAudioMixer.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,377 +0,0 @@ -package org.openjdk.sound; - -import java.io.File; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Semaphore; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Control; -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.Control.Type; - -public class PulseAudioMixer implements javax.sound.sampled.Mixer { - // singleton - - public EventLoop eventLoop; - public Thread eventLoopThread; - - private static PulseAudioMixer _instance = null; - - private static final String DEFAULT_APP_NAME = "Java App"; - - private boolean isOpen = false; - - private List<PulseAudioSourceDataLine> sourceLines = new ArrayList<PulseAudioSourceDataLine>(); - // private List<PulseAudioTargetDataLine> targetLines = null; - - private Line.Info sourceDataLineInfo = new Line.Info( - PulseAudioSourceDataLine.class); - // private Line.Info targetDataLineInfo = new - // Line.Info(PulseAudioTargetDataLine.class); - - List<LineListener> lineListeners = null; - - private PulseAudioMixer() { - lineListeners = new ArrayList<LineListener>(); - sourceLines = new ArrayList<PulseAudioSourceDataLine>(); - // _targetLines = new ArrayList<PulseAudioTargetDataLine>(); - } - - synchronized public static PulseAudioMixer getInstance() { - if (_instance == null) { - _instance = new PulseAudioMixer(); - } - return _instance; - } - - @Override - public Line getLine(javax.sound.sampled.Line.Info info) - throws LineUnavailableException { - - if (!this.isOpen) { - throw new LineUnavailableException(); - } - - if (info.matches(sourceDataLineInfo)) { - PulseAudioSourceDataLine sourceLine = null; - sourceLine = new PulseAudioSourceDataLine(eventLoop); - sourceLines.add(sourceLine); - return sourceLine; - } - - // if (info.matches(_targetDataLineInfo)) { - // PulseAudioTargetDataLine targetLine = new PulseAudioTargetDataLine(); - // _targetLines.add(targetLine); - // return targetLine; - // } - - throw new IllegalArgumentException(); - } - - @Override - public int getMaxLines(javax.sound.sampled.Line.Info info) { - return AudioSystem.NOT_SPECIFIED; - } - - @Override - public Info getMixerInfo() { - return PulseAudioMixerInfo.getInfo(); - } - - @Override - public javax.sound.sampled.Line.Info[] getSourceLineInfo() { - Line.Info[] info = { new Line.Info(PulseAudioSourceDataLine.class), }; - return info; - } - - @Override - public javax.sound.sampled.Line.Info[] getSourceLineInfo( - javax.sound.sampled.Line.Info info) { - Line.Info sourceInfo = new Line.Info(PulseAudioSourceDataLine.class); - if (info.matches(sourceInfo)) { - Line.Info[] sourceInfos = { sourceInfo, }; - return sourceInfos; - } else { - Line.Info[] sourceInfos = {}; - return sourceInfos; - - } - } - - @Override - public Line[] getSourceLines() { - // return (Line[]) _sourceLines.toArray(); - return null; - - } - - @Override - public javax.sound.sampled.Line.Info[] getTargetLineInfo() { - Line.Info[] info = { new Line.Info(PulseAudioTargetDataLine.class), }; - return info; - } - - @Override - public javax.sound.sampled.Line.Info[] getTargetLineInfo( - javax.sound.sampled.Line.Info info) { - Line.Info sourceInfo = new Line.Info(PulseAudioTargetDataLine.class); - if (info.matches(sourceInfo)) { - Line.Info[] sourceInfos = { sourceInfo, }; - return sourceInfos; - } else { - Line.Info[] sourceInfos = {}; - return sourceInfos; - } - } - - @Override - public Line[] getTargetLines() { - // return (Line[]) _targetLines.toArray(); - return null; - } - - @Override - public boolean isLineSupported(javax.sound.sampled.Line.Info info) { - // if ( _sourceDataLineInfo.matches(info)) { - // return true; - // } - return false; - } - - @Override - public boolean isSynchronizationSupported(Line[] lines, boolean maintainSync) { - // FIXME - return false; - } - - @Override - public void synchronize(Line[] lines, boolean maintainSync) { - // FIXME pulse audio supports this - throw new IllegalArgumentException(); - } - - @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() { - - if (!this.isOpen) { - return; // TODO do we throw an exception too? - } - - eventLoopThread.interrupt(); - - try { - eventLoop.finished.acquire(); - } catch (InterruptedException e) { - System.out.println(this.getClass().getName() - + ": interrupted while waiting for eventloop to finish"); - } - - System.out.println(this.getClass().getName() + ": closing"); - - this.isOpen = false; - fireEvent(new LineEvent(this, LineEvent.Type.CLOSE, - AudioSystem.NOT_SPECIFIED)); - - /* - * FIXME need to clean up the listeners on close without a race - * condition - */ - - } - - @Override - public Control getControl(Type control) { - return null; - } - - @Override - public Control[] getControls() { - return null; - } - - @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) { - // FIXME - return false; - } - - @Override - public boolean isOpen() { - return this.isOpen; - } - - @Override - public void open() throws LineUnavailableException { - openLocal(); - } - - public void open(String appName, String host) throws UnknownHostException, - LineUnavailableException { - openRemote(appName, host); - } - - public void openLocal() throws LineUnavailableException { - openLocal(DEFAULT_APP_NAME); - } - - public void openLocal(String appName) throws LineUnavailableException { - try { - openRemote(appName, null); - } catch (UnknownHostException e) { - // not possible - } - } - - public void openRemote(String appName, String host) - throws UnknownHostException, LineUnavailableException { - openRemote(appName, host, null); - } - - synchronized public void openRemote(String appName, String host, - Integer port) throws UnknownHostException, LineUnavailableException { - if (this.isOpen) { - return; - } - - InetAddress addr = InetAddress.getAllByName(host)[0]; - - if (port != null) { - host = addr.getHostAddress(); - host = host + ":" + String.valueOf(port); - } - - eventLoop = new EventLoop(); - eventLoop.setAppName(appName); - eventLoop.setServer(host); - - final Semaphore ready = new Semaphore(0); - - eventLoop.addContextListener(new ContextListener() { - - @Override - public void update(ContextEvent e) { - System.out.println("Event detected " + e.getType().toString()); - if (e.getType() == ContextEvent.Type.READY - || e.getType() == ContextEvent.Type.FAILED - || e.getType() == ContextEvent.Type.TERMINATED) { - ready.release(); - } - } - - }); - - eventLoopThread = new Thread(eventLoop, "PulseAudio Eventloop Thread"); - - eventLoopThread.setDaemon(false); - eventLoopThread.start(); - - try { - System.out.println("waiting..."); - ready.acquire(); - if (eventLoop.getStatus() != 4) { - throw new LineUnavailableException(); - } - - System.out.println("got signal"); - } catch (InterruptedException e) { - System.out.println("got interrupted"); - } - - this.isOpen = true; - fireEvent(new LineEvent(this, LineEvent.Type.OPEN, - AudioSystem.NOT_SPECIFIED)); - - } - - @Override - synchronized public void removeLineListener(LineListener listener) { - lineListeners.remove(listener); - } - - synchronized private void fireEvent(final LineEvent e) { - Thread th = new Thread(new Runnable() { - @Override - public void run() { - synchronized (lineListeners) { - for (LineListener lineListener : lineListeners) { - lineListener.update(e); - } - } - } - }); - th.start(); - } - - public static void main(String[] args) 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 selectedMixer = (PulseAudioMixer) AudioSystem - .getMixer(selectedMixerInfo); - - selectedMixer.open(); - SourceDataLine line = (SourceDataLine) selectedMixer - .getLine(new Line.Info(PulseAudioSourceDataLine.class)); - - System.out.println("got a line"); - - File soundFile = new File("new.wav"); - AudioInputStream audioInputStream = AudioSystem - .getAudioInputStream(soundFile); - AudioFormat audioFormat = audioInputStream.getFormat(); - 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); - } - } - - System.out.println("about to close"); - line.flush(); - selectedMixer.close(); - - } - -}
--- a/src/org/openjdk/sound/PulseAudioMixerInfo.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -package org.openjdk.sound; - -import javax.sound.sampled.Mixer; - -public 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", "openjdk", - "the ear-candy mixer", "0.01"); - } - - return _instance; - } - -}
--- a/src/org/openjdk/sound/PulseAudioMixerProvider.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -package org.openjdk.sound; - -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; - } - -}
--- a/src/org/openjdk/sound/PulseAudioSourceDataLine.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,356 +0,0 @@ -package org.openjdk.sound; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Semaphore; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.Control; -import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; -import javax.sound.sampled.LineListener; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.SourceDataLine; -import javax.sound.sampled.Control.Type; - -public class PulseAudioSourceDataLine implements SourceDataLine { - - private static final int DEFAULT_BUFFER_SIZE = 1000; - private String streamName = "Java Stream"; - private List<StreamListener> streamListeners = new ArrayList<StreamListener>(); - - private EventLoop eventLoop = null; - - private boolean isOpen = false; - private boolean isPaused = false; - - private AudioFormat format = null; - - private List<LineListener> listeners; - - /* - * When moving from 32bit platform to 64 bit platform, these variables that - * hold pointers will need their sizes changed - * - */ - @SuppressWarnings("unused") - private long streamPointer; - - private native void native_open(long contextPointer, String name, - String encoding, float rate, int size, int channels, - boolean bigEndian, int bufferSize); - - private native void native_write(byte[] data, int offset, int length); - - private native int native_get_writable_size(); - - private native int native_getOperationState(int operationState); - - private native int native_flush(); - - - private native void native_start(); - - private native void native_pause(); - - private native void native_resume(); - - - private native int native_drain(); - - private native void native_close(); - - static { - try { - String library = new java.io.File(".").getCanonicalPath() - + java.io.File.separatorChar + "lib" - + java.io.File.separatorChar - + System.mapLibraryName("pulse-java"); - System.out.println(library); - System.load(library); - } catch (IOException e) { - assert ("Loading failed".endsWith("library")); - } - } - - public PulseAudioSourceDataLine(EventLoop eventLoop) { - this.eventLoop = eventLoop; - this.listeners = new ArrayList<LineListener>(); - } - - public void open(AudioFormat format, int bufferSize) - throws LineUnavailableException { - isOpen = true; - - int channels = format.getChannels(); - float rate = format.getSampleRate(); - int sampleSize = format.getSampleSizeInBits(); - String encoding = format.getEncoding().toString(); - boolean bigEndian = format.isBigEndian(); - - synchronized (eventLoop.threadLock) { - native_open(eventLoop.getContextPointer(), streamName, encoding, - rate, sampleSize, channels, bigEndian, bufferSize); - } - } - - public void open(AudioFormat format) throws LineUnavailableException { - open(format, DEFAULT_BUFFER_SIZE); - - } - - public void open() throws LineUnavailableException { - format = new AudioFormat(44100, 16, 2, true, false); - open(format, DEFAULT_BUFFER_SIZE); - } - - @Override - public int write(byte[] data, int offset, int length) { - - int position = offset; - int remainingLength = length; - int availableSize; - - int sizeWritten = 0; - - while (remainingLength != 0) { - - synchronized (eventLoop.threadLock) { - availableSize = native_get_writable_size(); - if (availableSize < 0) { - return sizeWritten; - } - if (availableSize > remainingLength) { - availableSize = remainingLength; - } - /* write a little bit of the buffer */ - native_write(data, position, availableSize); - - sizeWritten += availableSize; - position += availableSize; - remainingLength -= availableSize; - - } - } - - // all the data should have been played by now - assert (sizeWritten == length); - - /* - * FIXME when the stream is flushed() etc, instead of returning length - * this should unblock and return the the size of data written so far - */ - return sizeWritten; - } - - public void start() { - if (isPaused) { - native_resume(); - isPaused = false; - return; - } else { - final Semaphore semaphore = new Semaphore(0); - - synchronized (eventLoop.threadLock) { - - this.addStreamListener(new StreamListener() { - @Override - public void update(StreamEvent e) { - System.out.println(this.getClass().getName() - + " waiting to stream to become ready"); - if (e.getType() == StreamEvent.Type.READY) { - semaphore.release(); - } - } - }); - - System.out.println("about to open stream"); - native_start(); - } - - try { - semaphore.acquire(); - } catch (InterruptedException e) { - // throw new LineUnavailableException("unable to prepare - // stream"); - } - System.out.println(this.getClass().getName() + "stream is ready"); - } - - /* - * for(LineListener l :listeners) { l.update(new LineEvent(this, - * LineEvent.Type.START, 0)); } - */ - } - - public void stop() { - synchronized (eventLoop.threadLock) { - native_pause(); - } - isPaused = true; - - } - - public void addLineListener(LineListener listener) { - this.listeners.add(listener); - } - - public void removeLineListener(LineListener listener) { - this.listeners.remove(listener); - } - - private void addStreamListener(StreamListener listener) { - this.streamListeners.add(listener); - } - - public boolean isOpen() { - return isOpen; - } - - public int available() { - synchronized (eventLoop.threadLock) { - return native_get_writable_size(); - } - }; - - public void close() { - synchronized (eventLoop.threadLock) { - native_close(); - } - - for (LineListener l : this.listeners) { - l.update(new LineEvent(this, LineEvent.Type.CLOSE, 0)); - } - - } - - public int getBufferSize() { - // TODO Auto-generated method stub - return 0; - } - - public AudioFormat getFormat() { - // TODO Auto-generated method stub - return null; - } - - public int getFramePosition() { - // TODO Auto-generated method stub - return 0; - } - - public float getLevel() { - // TODO Auto-generated method stub - return 0; - } - - public long getLongFramePosition() { - // TODO Auto-generated method stub - return 0; - } - - public long getMicrosecondPosition() { - // TODO Auto-generated method stub - return 0; - } - - public boolean isActive() { - // TODO Auto-generated method stub - return false; - } - - public boolean isRunning() { - // TODO Auto-generated method stub - return false; - } - - public Control getControl(Type control) { - // TODO Auto-generated method stub - return null; - } - - public Control[] getControls() { - // TODO Auto-generated method stub - return null; - } - - public javax.sound.sampled.Line.Info getLineInfo() { - return new Line.Info(SourceDataLine.class); - } - - public boolean isControlSupported(Type control) { - // TODO Auto-generated method stub - return false; - } - - @Override - public void drain() { - int operationPointer; - int operationState; - synchronized (eventLoop.threadLock) { - operationPointer = native_drain(); - operationState = native_getOperationState(operationPointer); - } - while(operationState != 1) { - synchronized (eventLoop.threadLock) { - operationState = native_getOperationState(operationPointer); - } - } - - } - - @Override - public void flush() { - int operationPointer; - int operationState; - synchronized (eventLoop.threadLock) { - operationPointer = native_flush(); - operationState = native_getOperationState(operationPointer); - } - while(operationState != 1) { - synchronized (eventLoop.threadLock) { - operationState = native_getOperationState(operationPointer); - } - } - - - } - - public void update(int status) { - synchronized (eventLoop.threadLock) { - System.out.println(this.getClass().getCanonicalName() - + ".update() called! status = " + status); - switch (status) { - case 0: - fireEvent(new StreamEvent( - org.openjdk.sound.StreamEvent.Type.UNCONNECTED)); - break; - case 1: - fireEvent(new StreamEvent( - org.openjdk.sound.StreamEvent.Type.CREATING)); - break; - case 2: - fireEvent(new StreamEvent( - org.openjdk.sound.StreamEvent.Type.READY)); - break; - case 3: - fireEvent(new StreamEvent( - org.openjdk.sound.StreamEvent.Type.FAILED)); - break; - case 4: - break; - default: - assert ("not supposed to happen".indexOf("false") >= 0); - } - } - } - - private void fireEvent(StreamEvent e) { - - for (StreamListener streamListener : streamListeners) { - streamListener.update(e); - } - } - -}
--- a/src/org/openjdk/sound/PulseAudioStreamVolumeControl.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -package org.openjdk.sound; - -import java.io.IOException; - -public class PulseAudioStreamVolumeControl extends PulseAudioVolumeControl { - private long streamPointer; - private long mainLoopPointer; - - static { - try { - String library = new java.io.File(".").getCanonicalPath() - + java.io.File.separatorChar + "lib" - + java.io.File.separatorChar - + System.mapLibraryName("pulse-java"); - System.out.println(library); - System.load(library); - } catch (IOException e) { - assert ("Loading failed".endsWith("library")); - } - } - - protected PulseAudioStreamVolumeControl(Type type, float minimum, - float maximum, float precision, int updatePeriod, - float initialValue, String units, long streamPointer, - long mainLoopPointer) { - super(type, minimum, maximum, precision, updatePeriod, initialValue, - units); - this.streamPointer = streamPointer; - this.mainLoopPointer = mainLoopPointer; - - } - - public native float getValue(); - - public native void setValue(float newValue); - -}
--- a/src/org/openjdk/sound/PulseAudioTargetDataLine.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -package org.openjdk.sound; - -import java.io.IOException; -import java.util.ArrayList; - -import javax.sound.sampled.*; -import javax.sound.sampled.Control.Type; - -public class PulseAudioTargetDataLine implements TargetDataLine { - - protected long contextPointer; - protected long mainLoopPointer; - protected long streamPointer; - protected boolean isOpen = false; - protected boolean isPaused = false; - protected int defaultBufferSize; - protected ArrayList<LineListener> listeners; - - static { - try { - String library = new java.io.File(".").getCanonicalPath() - + java.io.File.separatorChar + "lib" - + java.io.File.separatorChar - + System.mapLibraryName("pulse-java"); - System.out.println(library); - System.load(library); - } catch (IOException e) { - assert ("Loading failed".endsWith("library")); - } - } - - public void open(AudioFormat format, int bufferSize) - throws LineUnavailableException { - isOpen = true; - - int channels = format.getChannels(); - float rate = format.getSampleRate(); - int sampleSize = format.getSampleSizeInBits(); - String encoding = format.getEncoding().toString(); - boolean bigEndian = format.isBigEndian(); - openStream(encoding, rate, sampleSize, channels, bigEndian, bufferSize); - } - - public void open(AudioFormat format) throws LineUnavailableException { - open(format, defaultBufferSize); - - } - - public void open() throws LineUnavailableException { - openStream("PCM_SIGNED", 44100, 16, 2, false, defaultBufferSize); - } - - private native void openStream(String encoding, float rate, int size, - int channels, boolean bigEndian, int bufferSize); - - static { - System.loadLibrary("PulseAudioSourceDataLine"); - } - - @Override - public int read(byte[] b, int off, int len) { - readFromStream(b, off, len); - return len; - } - - private native void readFromStream(byte[] b, int off, int len); - - public void start() { - if (isPaused) { - resumeStream(); - isPaused = false; - } else { - startStream(); - } - - for (LineListener l : listeners) { - l.update(new LineEvent(this, LineEvent.Type.START, 0)); - } - } - - public void stop() { - pauseStream(); - isPaused = true; - - } - - private native void startStream(); - - private native void pauseStream(); - - private native void resumeStream(); - - @Override - public void drain() { - // TODO Auto-generated method stub - - } - - @Override - public void flush() { - // TODO Auto-generated method stub - - } - - public void addLineListener(LineListener listener) { - listeners.add(listener); - } - - public void removeLineListener(LineListener listener) { - listeners.remove(listener); - } - - public boolean isOpen() { - return isOpen; - } - - public native int available(); - - public void close() { - closeStream(); - for (LineListener l : listeners) { - l.update(new LineEvent(this, LineEvent.Type.CLOSE, 0)); - } - - } - - private native void closeStream(); - - public int getBufferSize() { - // TODO Auto-generated method stub - return 0; - } - - public AudioFormat getFormat() { - // TODO Auto-generated method stub - return null; - } - - public int getFramePosition() { - // TODO Auto-generated method stub - return 0; - } - - public float getLevel() { - // TODO Auto-generated method stub - return 0; - } - - public long getLongFramePosition() { - // TODO Auto-generated method stub - return 0; - } - - public long getMicrosecondPosition() { - // TODO Auto-generated method stub - return 0; - } - - public boolean isActive() { - // TODO Auto-generated method stub - return false; - } - - public boolean isRunning() { - // TODO Auto-generated method stub - return false; - } - - public Control getControl(Type control) { - // TODO Auto-generated method stub - return null; - } - - public Control[] getControls() { - // TODO Auto-generated method stub - return null; - } - - public javax.sound.sampled.Line.Info getLineInfo() { - return new Line.Info(SourceDataLine.class); - } - - public boolean isControlSupported(Type control) { - // TODO Auto-generated method stub - return false; - } - -}
--- a/src/org/openjdk/sound/PulseAudioVolumeControl.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -package org.openjdk.sound; - -import javax.sound.sampled.FloatControl; -import javax.sound.sampled.FloatControl.Type; - -public class PulseAudioVolumeControl extends FloatControl { - - protected PulseAudioVolumeControl(Type type, float minimum, float maximum, - float precision, int updatePeriod, float initialValue, String units) { - super(type, minimum, maximum, precision, updatePeriod, initialValue, - units); - - } - - public native float getMaximum(); - -}
--- a/src/org/openjdk/sound/StreamEvent.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -package org.openjdk.sound; - -public class StreamEvent { - - public static enum Type { - UNCONNECTED, CREATING, READY, FAILED, TERMINATED, - } - - - private Type type; - - public StreamEvent(StreamEvent.Type type) { - this.type = type; - } - - public Type getType() { - return this.type; - } - -}
--- a/src/org/openjdk/sound/StreamListener.java Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -package org.openjdk.sound; - - -public interface StreamListener{ - - public void update(StreamEvent e); - -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_EventLoop.c Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,278 @@ +/* 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 <pulse/pulseaudio.h> + +#include "org_classpath_icedtea_pulseaudio_EventLoop.h" +#include "jni-common.h" + +const int PA_ITERATE_BLOCK = 1; +const int PA_ITERATE_NOBLOCK = 0; + +typedef struct java_context_t { + JNIEnv* env; + jobject obj; +} java_context_t; + +static java_context_t* java_context = NULL; + +JNIEnv* pulse_thread_env = NULL; + +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 'update' method in java + * to handle all java-side events + */ + jclass cls = (*env)->GetObjectClass(env, obj); + if (cls == NULL) { + printf("unable to get class of object"); + return; + } + jmethodID mid = (*env)->GetMethodID(env, cls, "update", "(I)V"); + if (mid == NULL) { + printf("unable to get callback method\n"); + return; + + } + (*env)->CallVoidMethod(env, obj, mid, pa_context_get_state(context)); + return; + +} + +/* + * 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); + + jfieldID fid; /* the field id */ + jclass cls = (*env)->GetObjectClass(env,obj); + + 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 jbyte* 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 jbyte* 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); + } + + 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; + +} + +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"); + + jfieldID fid; /* the field id */ + jclass cls = (*env)->GetObjectClass(env,obj); + + 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); + } + + (*env)->DeleteGlobalRef(env, java_context->obj); + + free(java_context); + + printf("native_shutdown() returning\n"); + +} + +static void sink_input_volume_change_complete(pa_context* contest, int success, + void* userdata) { + // userdata is the pointer to the int containing the new volume + + assert(userdata); + free(userdata); + assert(success); + printf("volume change complete\n"); + +} + +static void sink_input_change_volume(pa_context* c, + const pa_sink_input_info* i, int eol, void* userdata) { + assert(c); + + // end of list ? + if (eol) { + return; + } + + assert(i); + assert(userdata); + int volume = *((int*)userdata); + + int j = 0; + // printf("changing sink input volume\n"); + pa_cvolume* new_volume = malloc(sizeof(pa_cvolume)); + + // printf("allocated memory\n"); + new_volume->channels = i->volume.channels; + // printf("set the number of channels\n"); + for (j = 0; j < new_volume->channels; j++) { + new_volume->values[j] = volume; + } + + // printf("calling set_sick_input_volume\n"); + pa_operation* o = pa_context_set_sink_input_volume(c, i->index, new_volume, + sink_input_volume_change_complete, new_volume); + if (o != NULL) { + pa_operation_unref(o); + } + + // printf("done setup for changing volume\n"); +} + +/* + * Class: org_classpath_icedtea_pulseaudio_EventLoop + * Method: native_set_sink_volume + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_EventLoop_native_1set_1sink_1volume +(JNIEnv* env, jobject obj, jlong streamPointer, jint volume) { + int* new_volume = malloc(sizeof(int)); + *new_volume = volume; + int stream_id = pa_stream_get_index((pa_stream*) convertFromJavaPointer(streamPointer)); + pa_context_get_sink_input_info((pa_context*) getJavaPointer(env, obj,"contextPointer") ,stream_id,sink_input_change_volume, new_volume); + return; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_EventLoop.h Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,45 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class org_classpath_icedtea_pulseaudio_EventLoop */ + +#ifndef _Included_org_classpath_icedtea_pulseaudio_EventLoop +#define _Included_org_classpath_icedtea_pulseaudio_EventLoop +#ifdef __cplusplus +extern "C" { +#endif +/* + * 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 *, jobject, jstring, jstring); + +/* + * Class: org_classpath_icedtea_pulseaudio_EventLoop + * Method: native_iterate + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_EventLoop_native_1iterate + (JNIEnv *, jobject, jint); + +/* + * Class: org_classpath_icedtea_pulseaudio_EventLoop + * Method: native_shutdown + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_EventLoop_native_1shutdown + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_EventLoop + * Method: native_set_sink_volume + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_EventLoop_native_1set_1sink_1volume + (JNIEnv *, jobject, jlong, jint); + +#ifdef __cplusplus +} +#endif +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.c Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,286 @@ +/* org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.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 <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <jni.h> +#include <pulse/pulseaudio.h> + +#include "org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.h" +#include "jni-common.h" + +typedef struct java_context_t { + JNIEnv* env; + jobject obj; +} java_context_t; + +static java_context_t* java_context; + +/* defined in EventLoop.c */ +extern JNIEnv* pulse_thread_env; + +static void stream_drain_complete_callback(pa_stream* stream, int success, + void* userdata) { + assert(stream); + assert(success != 0); + + pa_stream_disconnect(stream); +} + +static void stream_state_change_callback(pa_stream* stream, void* userdata) { + assert(stream); + assert(userdata); + + printf("entering stream_state_change_callback\n"); + + java_context_t* java_context = (java_context_t*)userdata; + JNIEnv* env; + + /* needed so we can create a stream from another thread + */ + if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { + printf("java thread\n"); + env = java_context->env; + } else { + env = pulse_thread_env; + } + + jobject obj = java_context->obj; + + printf("stream state changed to %d\n", pa_stream_get_state(stream)); + + /* Call the 'update' method in java + * to handle all java-side events + */ + jclass cls = (*env)->GetObjectClass(env, obj); + if (cls == NULL) { + printf("unable to get class of object"); + return; + } + jmethodID mid = (*env)->GetMethodID(env, cls, "update", "(I)V"); + if (mid == NULL) { + printf("unable to get callback method\n"); + return; + + } + printf("calling update on java\n"); + (*env)->CallVoidMethod(env, obj, mid, pa_stream_get_state(stream)); + + printf("returning form stream_state_change_callback\n"); + return; + +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_open + * Signature: (JLjava/lang/String;Ljava/lang/String;FIIZI)V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1open +(JNIEnv* env, jobject obj, jlong contextPointer, jstring name, jstring encodingString, jfloat rate, jint size, jint channels, jboolean bigEndian, jint bufferSize) { + + //TODO: Need to deal with the buffer size. Currently ignored + + printf("entering native_open\n"); + java_context_t* java_context = malloc(sizeof(java_context)); + java_context->env = env; + java_context->obj = (*env)->NewGlobalRef(env, obj); + + pa_context* context = (pa_context*) convertFromJavaPointer(contextPointer); + assert(context != NULL); + + pa_sample_spec sample_spec; + + const char *encoding = (*env)->GetStringUTFChars(env, encodingString, NULL); + + if( (strcmp(encoding, "PCM_UNSIGNED") == 0) && (size == 8)) { + sample_spec.format = PA_SAMPLE_U8; + } else if( (strcmp(encoding, "ALAW") == 0) && (size == 8)) { + sample_spec.format = PA_SAMPLE_ALAW; + } else if( (strcmp(encoding, "ULAW") == 0) && (size == 8)) { + sample_spec.format = PA_SAMPLE_ULAW; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 1)) { + sample_spec.format = PA_SAMPLE_S16BE; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 0)) { + sample_spec.format = PA_SAMPLE_S16LE; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 1)) { + sample_spec.format = PA_SAMPLE_S32BE; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 0)) { + sample_spec.format = PA_SAMPLE_S32LE; + } else { + printf("error in open"); + throwByName(env, "IllegalArgumentException", "Invalid format"); + /* clean up */ + free(java_context); + return; + } + + (*env)->ReleaseStringUTFChars(env, encodingString, encoding); + + sample_spec.rate = rate; + sample_spec.channels = channels; + + /* obtain the server from the caller */ + const jbyte* stream_name = NULL; + stream_name = (*env)->GetStringUTFChars(env, name, NULL); + if (stream_name == NULL) { + return; /* OutOfMemoryError */ + } + printf("About to create stream: %s\n", stream_name); + pa_stream* stream = pa_stream_new(context, stream_name, &sample_spec, NULL); + assert(stream != NULL); + (*env)->ReleaseStringUTFChars(env, name, stream_name); + + pa_stream_set_state_callback(stream, stream_state_change_callback, java_context); + + setJavaPointer(env, obj, "streamPointer", stream); + printf("returning from native_open\n"); + +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_write + * Signature: ([BII)V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1write +(JNIEnv* env, jobject obj, jbyteArray data, jint offset, jint data_length) { + + pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, "streamPointer"); + jbyte* data_buffer = (*env)->GetByteArrayElements(env, data, NULL); + jbyte* buffer_start = data_buffer + offset; + pa_stream_write(stream, buffer_start, data_length, NULL, 0, PA_SEEK_RELATIVE); + (*env)->ReleaseByteArrayElements(env, data, data_buffer, 0); + +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_get_writable_size + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1get_1writable_1size +(JNIEnv* env, jobject obj) { + + pa_stream *stream = (pa_stream*) getJavaPointer(env, obj, "streamPointer"); + int available = pa_stream_writable_size(stream); + +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_flush + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1flush +(JNIEnv* env, jobject obj) { + + pa_stream *stream = (pa_stream*) getJavaPointer(env, obj, "streamPointer"); + pa_operation *o = pa_stream_flush(stream, NULL, NULL); + return (int) o; + +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_getOperationState + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1getOperationState +(JNIEnv *env, jobject obj, jint operation) { + + return pa_operation_get_state((pa_operation *) operation); + +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_start + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1start +(JNIEnv *env, jobject obj) { + printf("start called\n"); + + pa_stream *stream = (pa_stream*)getJavaPointer(env, obj, "streamPointer"); + pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL); + +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_pause + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1pause +(JNIEnv* env, jobject obj) { + +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_resume + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1resume +(JNIEnv* env, jobject obj) { + +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_drain + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1drain +(JNIEnv* env, jobject obj) { + pa_stream *stream = (pa_stream*) getJavaPointer(env, obj, "streamPointer"); + pa_operation *o = pa_stream_drain(stream, NULL, NULL); + return (int) o; +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1close +(JNIEnv* env, jobject obj) { + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.h Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,95 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine */ + +#ifndef _Included_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine +#define _Included_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine +#ifdef __cplusplus +extern "C" { +#endif +#undef org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_DEFAULT_BUFFER_SIZE +#define org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_DEFAULT_BUFFER_SIZE 1000L +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_open + * Signature: (JLjava/lang/String;Ljava/lang/String;FIIZI)V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1open + (JNIEnv *, jobject, jlong, jstring, jstring, jfloat, jint, jint, jboolean, jint); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_write + * Signature: ([BII)V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1write + (JNIEnv *, jobject, jbyteArray, jint, jint); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_get_writable_size + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1get_1writable_1size + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_getOperationState + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1getOperationState + (JNIEnv *, jobject, jint); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_flush + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1flush + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_start + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1start + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_pause + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1pause + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_resume + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1resume + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_drain + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1drain + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine + * Method: native_close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine_native_1close + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl.c Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,106 @@ +/* org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl.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 <jni.h> +#include <pulse/pulseaudio.h> +#include "org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl.h" + +typedef struct { + pa_threaded_mainloop *mainloop; + pa_cvolume *volume; +} userdata_info; + +static void sink_input_change_volume(pa_context* context, + const pa_sink_input_info* sink_input_info, int eol, void* userdata) { + assert(context); + if (eol) { + return; + } + assert(sink_input_info); + + (((userdata_info *) userdata)->volume)->channels + = sink_input_info->volume.channels; + int j; + for (j = 0; j < (((userdata_info *)userdata)->volume)->channels; j++) { + (((userdata_info *)userdata)->volume)->values[j] + = sink_input_info->volume.values[j]; + } + pa_threaded_mainloop_signal(((userdata_info *) userdata)->mainloop, 0); + +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl + * Method: getValue + * Signature: ()F + */ +JNIEXPORT jfloat JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl_getValue +(JNIEnv *env, jobject obj) { + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop *mainloop = getJavaLongField(env, obj, "mainLoopPointer"); + pa_context *context = pa_stream_get_context(stream); + int stream_id = pa_stream_get_index(stream); + + userdata_info *userdata = malloc(sizeof(userdata_info)); + userdata->mainloop = mainloop; + userdata->volume = malloc(sizeof(pa_cvolume)); + pa_threaded_mainloop_lock(mainloop); + pa_operation *o = pa_context_get_sink_input_info((pa_context*) context ,stream_id,sink_input_change_volume, userdata); + while(pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(mainloop); + } + pa_operation_unref(o); + pa_threaded_mainloop_unlock(mainloop); + return pa_sw_volume_to_dB(userdata->volume->values[0]); + +} + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl + * Method: setValue + * Signature: (F)V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl_setValue +(JNIEnv *env, jobject obj, jfloat new_volume) { + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_context *context = pa_stream_get_context(stream); + int stream_id = pa_stream_get_index(stream); + int channels = pa_stream_get_sample_spec(stream)->channels; + pa_cvolume cv; + pa_context_set_sink_input_by_index(context, stream_id, pa_cvolume_set(&cv, channels, pa_sw_volume_from_dB(new_volume)), NULL, NULL); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl.h Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,29 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl */ + +#ifndef _Included_org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl +#define _Included_org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl + * Method: getValue + * Signature: ()F + */ +JNIEXPORT jfloat JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl_getValue + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl + * Method: setValue + * Signature: (F)V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioStreamVolumeControl_setValue + (JNIEnv *, jobject, jfloat); + +#ifdef __cplusplus +} +#endif +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine.c Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,267 @@ +/* org_org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine.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 <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <jni.h> +#include <pulse/pulseaudio.h> +#include <string.h> + +#include "org_org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine.h" +#include "jni-common.h" + +static void stream_read_cb(pa_stream* stream, size_t length, void* userdata) { + pa_threaded_mainloop *mainloop = userdata; + pa_threaded_mainloop_signal(mainloop, 0); +} + +static void stream_operation_complete_cb(pa_stream* stream, int success, + void* userdata) { + pa_threaded_mainloop *mainloop = userdata; + pa_threaded_mainloop_signal(mainloop, 0); +} + +static void stream_state_cb(pa_stream* stream, void* userdata) { + assert(stream); + pa_threaded_mainloop *mainloop = userdata; + printf("stream state changed to %d\n", pa_stream_get_state(stream)); + switch (pa_stream_get_state(stream)) { + case PA_STREAM_READY: + case PA_STREAM_FAILED: + case PA_STREAM_TERMINATED: + pa_threaded_mainloop_signal(mainloop, 0); + break; + + default: + /* do nothing */ + break; + } +} + +JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_openStream +(JNIEnv * env, jobject obj, jstring string, jfloat rate, jint size, jint channels, jboolean bigEndian, jint bufferSize) { + + printf("entering native_open\n"); + + pa_context* context = (pa_context*) contextPointer; + assert(context != NULL); + + obj = (*env)->NewGlobalRef(env, obj); + + java_context_t* java_context = malloc(sizeof(java_context)); + java_context->env = env; + java_context->obj = obj; + + //TODO: Need to deal with the buffer size. Currently ignored + + pa_sample_spec sample_spec; + + char *encoding = GetStringUTFChars(env, string, NULL); + + if( (strcmp(encoding, "PCM_UNSIGNED") == 0) && (size == 8)) { + sample_spec.format = PA_SAMPLE_U8; + } else if( (strcmp(encoding, "ALAW") == 0) && (size == 8)) { + sample_spec.format = PA_SAMPLE_ALAW; + } else if( (strcmp(encoding, "ULAW") == 0) && (size == 8)) { + sample_spec.format = PA_SAMPLE_ULAW; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 1)) { + sample_spec.format = PA_SAMPLE_S16BE; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 0)) { + sample_spec.format = PA_SAMPLE_S16LE; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 1)) { + sample_spec.format = PA_SAMPLE_S32BE; + } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 0)) { + sample_spec.format = PA_SAMPLE_S32LE; + } else { + //TODO: Invalid format :throw Exception; + } + + sample_spec.rate = rate; + sample_spec.channels = channels; + + /* obtain the server from the caller */ + const jbyte* stream_name = NULL; + stream_name = (*env)->GetStringUTFChars(env, name, NULL); + if (stream_name == NULL) { + return; /* OutOfMemoryError */ + } + printf("About to create stream: %s\n", stream_name); + pa_stream* stream = pa_stream_new(context, stream_name, &sample_spec, NULL); + assert(stream != NULL); + (*env)->ReleaseStringUTFChars(env, name, stream_name); + + pa_stream_set_state_callback(stream, stream_state_change_callback, java_context); + + jclass cls = (*env)->GetObjectClass(env,obj); + jfieldID fid = (*env)->GetFieldID(env, cls, "streamPointer", "I"); + (*env)->SetIntField(env, obj, fid, (jint) stream); + + printf("returning from native_open\n"); + +} + +JNIEXPORT void JNICALL +Java_org_openjdk_sound_PulseAudioSourceDataLine_startStream(JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL); + pa_threaded_mainloop_wait(mainloop); + if ( pa_stream_get_state(stream) != PA_STREAM_READY ) { + printf("stream initialization failed\n"); + } + pa_threaded_mainloop_unlock(mainloop); +} + +JNIEXPORT void Java_org_openjdk_sound_PulseAudioSourceDataLine_resumeStream( + JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField(env, obj, + "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + pa_operation *o = pa_stream_cork(stream, 0, stream_operation_complete_cb, + mainloop); + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(mainloop); + } + pa_operation_unref(o); + pa_threaded_mainloop_unlock(mainloop); + +} + +JNIEXPORT void Java_org_openjdk_sound_PulseAudioSourceDataLine__pauseStream( + JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField(env, obj, + "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + pa_operation *o = pa_stream_cork(stream, 1, stream_operation_complete_cb, + mainloop); + while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(mainloop); + } + pa_operation_unref(o); + pa_threaded_mainloop_unlock(mainloop); +} + +J + +JNIEXPORT void JNICALL +Java_org_openjdk_sound_PulseAudioSourceDataLine__closeStream(JNIEnv *env, jobject obj, jint channels, jfloat rate) { + + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_strean_disconnect(stream); +} + +JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_available +(JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + int available = pa_stream_writable_size(stream); + pa_threaded_mainloop_unlock(mainloop); + return available; +} + +JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_drain +(JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + pa_operation *o = pa_stream_drain(stream, stream_operation_complete_cb, mainloop); + while(pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(mainloop); + } + pa_operation_unref(o); + pa_threaded_mainloop_unlock(mainloop); +} + +JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_flush +(JNIEnv *env, jobject obj) { + pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + pa_threaded_mainloop_lock(mainloop); + pa_operation *o = pa_stream_flush(stream, stream_operation_complete_cb, mainloop); + while(pa_operation_get_state(o) != PA_OPERATION_DONE) { + pa_threaded_mainloop_wait(mainloop); + } + pa_operation_unref(o); + pa_threaded_mainloop_unlock(mainloop); +} + +JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioTargetDataLine_readFromStream +(JNIEnv * env, jobject obj, jbyteArray array, jint length, jint offset); +pa_threaded_mainloop *mainloop = getJavaLongField(env, obj, "mainLoopPointer"); +pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); +pa_threaded_mainloop_lock(mainloop); +char[length] data; +while(length> 0) { + size_t l; + while(!read_data) { + int r = pa_stream_peek(_stream, &read_data, &read_length); + if(!read_data) { + pa_threaded_mainloop_wait(mainloop); + } else { + read_index = 0; + } + } + + l = read_length < length ? read_length : length; + memcpy(data, read_data+read_index, l); + + data = data + l; + length -= l; + read_index +=l; + read_length-=l; + + if(! read_length) { + int r = pa_stream_drop(stream); + read_data = NULL; + read_length = 0; + read_index = 0; + + } + +} + +pa_threaded_mainloop_unlock(mainloop); +SetByteArrayRegion(env, array, offset, initialLength, data); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine.h Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,69 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine */ + +#ifndef _Included_org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine +#define _Included_org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine + * Method: openStream + * Signature: (Ljava/lang/String;FIIZI)V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine_openStream + (JNIEnv *, jobject, jstring, jfloat, jint, jint, jboolean, jint); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine + * Method: readFromStream + * Signature: ([BII)V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine_readFromStream + (JNIEnv *, jobject, jbyteArray, jint, jint); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine + * Method: startStream + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine_startStream + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine + * Method: pauseStream + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine_pauseStream + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine + * Method: resumeStream + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine_resumeStream + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine + * Method: available + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine_available + (JNIEnv *, jobject); + +/* + * Class: org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine + * Method: closeStream + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_classpath_icedtea_pulseaudio_PulseAudioTargetDataLine_closeStream + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_PulseAudioVolumeControl.c Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,39 @@ +/* org_classpath_icedtea_pulseaudio_PulseAudioVolumeControl.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_PulseAudioVolumeControl.h" \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_PulseAudioVolumeControl.h Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,13 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class org_classpath_icedtea_pulseaudio_PulseAudioVolumeControl */ + +#ifndef _Included_org_classpath_icedtea_pulseaudio_PulseAudioVolumeControl +#define _Included_org_classpath_icedtea_pulseaudio_PulseAudioVolumeControl +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_PulseAudioVolumeMuteControl.c Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,63 @@ +/* PulseAudioStreamVolumeControl.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. +*/ + + +void *getJavaLongField(JNIEnv *env, jobject obj, char *fieldName) { + jclass cls = (*env)->GetObjectClass(env, obj); + jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "J"); + jlong value = (*env)->GetLongField(env, obj, fid); + //(*env)->DeleteLocalReference(cls); + return (void *) value; +} + +static void sink_input_change_volume(pa_context* context, + const pa_sink_input_info* input_info, int eol, void* userdata) { + assert(context); + if (eol) { + return; + } + assert(i); + userdata = i->volume; +} + +JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioStreamVolumeControl_getValue(JNIEnv env*, jobject obj) { + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + int stream_id pa_stream_get_index(stream); + pa_cvolume *volume; + pa_context_get_sink_input_info((pa_context*) contextPointer ,stream_id,sink_input_change_volume, volume); + printf("%d\n", volume->values[0]); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org_classpath_icedtea_pulseaudio_PulseStreamAudioVolumeControl.c Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,61 @@ +/* PulseAudioStreamVolumeControl.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. +*/ + + void *getJavaLongField(JNIEnv *env, jobject obj, char *fieldName) { + jclass cls = (*env)->GetObjectClass(env, obj); + jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "J"); + jlong value = (*env)->GetLongField(env, obj, fid); + //(*env)->DeleteLocalReference(cls); + return (void *) value; +} + +static void sink_input_change_volume(pa_context* context, const pa_sink_input_info* input_info, int eol, void* userdata) { + assert(context); + if (eol) { + return; + } + assert(i); + userdata = i->volume; +} + +JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioStreamVolumeControl_getValue(JNIEnv env*, jobject obj) { + pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); + int stream_id pa_stream_get_index(stream); + pa_cvolume *volume; + pa_context_get_sink_input_info((pa_context*) contextPointer ,stream_id,sink_input_change_volume, volume); + printf("%d\n", volume->values[0]); +}
--- a/src/org_openjdk_sound_EventLoop.c Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,237 +0,0 @@ -#include <pulse/pulseaudio.h> - -#include "org_openjdk_sound_EventLoop.h" -#include "jni-common.h" - -const int PA_ITERATE_BLOCK = 1; -const int PA_ITERATE_NOBLOCK = 0; - -typedef struct java_context_t { - JNIEnv* env; - jobject obj; -} java_context_t; - -static java_context_t* java_context = NULL; - -JNIEnv* pulse_thread_env = NULL; - -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 'update' method in java - * to handle all java-side events - */ - jclass cls = (*env)->GetObjectClass(env, obj); - if (cls == NULL) { - printf("unable to get class of object"); - return; - } - jmethodID mid = (*env)->GetMethodID(env, cls, "update", "(I)V"); - if (mid == NULL) { - printf("unable to get callback method\n"); - return; - - } - (*env)->CallVoidMethod(env, obj, mid, pa_context_get_state(context)); - return; - -} - -/* - * Class: org_openjdk_sound_EventLoop - * Method: native_setup - * Signature: (Ljava/lang/String;Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1setup -(JNIEnv* env, jobject obj, jstring appName, jstring server) { - - assert(appName != NULL); - - jfieldID fid; /* the field id */ - jclass cls = (*env)->GetObjectClass(env,obj); - - 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 jbyte* 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 jbyte* string_server = NULL; - string_server = (*env)->GetStringUTFChars(env, server, NULL); - if (string_server == NULL) { - 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); - } - - setJavaPointer(env, obj, "mainloopPointer", mainloop); - setJavaPointer(env, obj, "contextPointer", context); - printf("native_setup() returning\n"); - return; - -} - -/* - * Class: org_openjdk_sound_EventLoop - * Method: native_iterate - * Signature: (I)I - */ -JNIEXPORT jint JNICALL Java_org_openjdk_sound_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; - -} - -static void context_drain_complete_callback(pa_context* context, void* userdata) { - pa_context_disconnect(context); - -} - -/* - * Class: org_openjdk_sound_EventLoop - * Method: native_shutdown - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1shutdown -(JNIEnv *env, jobject obj) { - - printf("native_shutdown() starting\n"); - - jfieldID fid; /* the field id */ - jclass cls = (*env)->GetObjectClass(env,obj); - - 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); - } - - (*env)->DeleteGlobalRef(env, java_context->obj); - - free(java_context); - - printf("native_shutdown() returning\n"); - -} - -static void sink_input_volume_change_complete(pa_context* contest, int success, - void* userdata) { - // userdata is the pointer to the int containing the new volume - - assert(userdata); - free(userdata); - assert(success); - printf("volume change complete\n"); - -} - -static void sink_input_change_volume(pa_context* c, - const pa_sink_input_info* i, int eol, void* userdata) { - assert(c); - - // end of list ? - if (eol) { - return; - } - - assert(i); - assert(userdata); - int volume = *((int*)userdata); - - int j = 0; - // printf("changing sink input volume\n"); - pa_cvolume* new_volume = malloc(sizeof(pa_cvolume)); - - // printf("allocated memory\n"); - new_volume->channels = i->volume.channels; - // printf("set the number of channels\n"); - for (j = 0; j < new_volume->channels; j++) { - new_volume->values[j] = volume; - } - - // printf("calling set_sick_input_volume\n"); - pa_operation* o = pa_context_set_sink_input_volume(c, i->index, new_volume, - sink_input_volume_change_complete, new_volume); - if (o != NULL) { - pa_operation_unref(o); - } - - // printf("done setup for changing volume\n"); -} - -/* - * Class: org_openjdk_sound_EventLoop - * Method: native_set_sink_volume - * Signature: (II)V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1set_1sink_1volume -(JNIEnv* env, jobject obj, jlong streamPointer, jint volume) { - - int* new_volume = malloc(sizeof(int)); - *new_volume = volume; - int stream_id = pa_stream_get_index((pa_stream*) convertFromJavaPointer(streamPointer)); - pa_context_get_sink_input_info((pa_context*) getJavaPointer(env, obj,"contextPointer") ,stream_id,sink_input_change_volume, new_volume); - return; -} -
--- a/src/org_openjdk_sound_EventLoop.h Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include <jni.h> -/* Header for class org_openjdk_sound_EventLoop */ - -#ifndef _Included_org_openjdk_sound_EventLoop -#define _Included_org_openjdk_sound_EventLoop -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: org_openjdk_sound_EventLoop - * Method: native_setup - * Signature: (Ljava/lang/String;Ljava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1setup - (JNIEnv *, jobject, jstring, jstring); - -/* - * Class: org_openjdk_sound_EventLoop - * Method: native_iterate - * Signature: (I)I - */ -JNIEXPORT jint JNICALL Java_org_openjdk_sound_EventLoop_native_1iterate - (JNIEnv *, jobject, jint); - -/* - * Class: org_openjdk_sound_EventLoop - * Method: native_shutdown - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1shutdown - (JNIEnv *, jobject); - -/* - * Class: org_openjdk_sound_EventLoop - * Method: native_set_sink_volume - * Signature: (JI)V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1set_1sink_1volume - (JNIEnv *, jobject, jlong, jint); - -#ifdef __cplusplus -} -#endif -#endif
--- a/src/org_openjdk_sound_PulseAudioSourceDataLine.c Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <jni.h> -#include <pulse/pulseaudio.h> - -#include "org_openjdk_sound_PulseAudioSourceDataLine.h" -#include "jni-common.h" - -typedef struct java_context_t { - JNIEnv* env; - jobject obj; -} java_context_t; - -static java_context_t* java_context; - -/* defined in EventLoop.c */ -extern JNIEnv* pulse_thread_env; - -static void stream_drain_complete_callback(pa_stream* stream, int success, - void* userdata) { - assert(stream); - assert(success != 0); - - pa_stream_disconnect(stream); -} - -static void stream_state_change_callback(pa_stream* stream, void* userdata) { - assert(stream); - assert(userdata); - - printf("entering stream_state_change_callback\n"); - - java_context_t* java_context = (java_context_t*)userdata; - JNIEnv* env; - - /* needed so we can create a stream from another thread - */ - if (pa_stream_get_state(stream) == PA_STREAM_CREATING) { - printf("java thread\n"); - env = java_context->env; - } else { - env = pulse_thread_env; - } - - jobject obj = java_context->obj; - - printf("stream state changed to %d\n", pa_stream_get_state(stream)); - - /* Call the 'update' method in java - * to handle all java-side events - */ - jclass cls = (*env)->GetObjectClass(env, obj); - if (cls == NULL) { - printf("unable to get class of object"); - return; - } - jmethodID mid = (*env)->GetMethodID(env, cls, "update", "(I)V"); - if (mid == NULL) { - printf("unable to get callback method\n"); - return; - - } - printf("calling update on java\n"); - (*env)->CallVoidMethod(env, obj, mid, pa_stream_get_state(stream)); - - printf("returning form stream_state_change_callback\n"); - return; - -} - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_open - * Signature: (JLjava/lang/String;Ljava/lang/String;FIIZI)V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1open -(JNIEnv* env, jobject obj, jlong contextPointer, jstring name, jstring encodingString, jfloat rate, jint size, jint channels, jboolean bigEndian, jint bufferSize) { - - //TODO: Need to deal with the buffer size. Currently ignored - - printf("entering native_open\n"); - java_context_t* java_context = malloc(sizeof(java_context)); - java_context->env = env; - java_context->obj = (*env)->NewGlobalRef(env, obj); - - pa_context* context = (pa_context*) convertFromJavaPointer(contextPointer); - assert(context != NULL); - - pa_sample_spec sample_spec; - - const char *encoding = (*env)->GetStringUTFChars(env, encodingString, NULL); - - if( (strcmp(encoding, "PCM_UNSIGNED") == 0) && (size == 8)) { - sample_spec.format = PA_SAMPLE_U8; - } else if( (strcmp(encoding, "ALAW") == 0) && (size == 8)) { - sample_spec.format = PA_SAMPLE_ALAW; - } else if( (strcmp(encoding, "ULAW") == 0) && (size == 8)) { - sample_spec.format = PA_SAMPLE_ULAW; - } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 1)) { - sample_spec.format = PA_SAMPLE_S16BE; - } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 0)) { - sample_spec.format = PA_SAMPLE_S16LE; - } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 1)) { - sample_spec.format = PA_SAMPLE_S32BE; - } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 0)) { - sample_spec.format = PA_SAMPLE_S32LE; - } else { - printf("error in open"); - //TODO: Invalid format :throw Exception; - } - - sample_spec.rate = rate; - sample_spec.channels = channels; - - /* obtain the server from the caller */ - const jbyte* stream_name = NULL; - stream_name = (*env)->GetStringUTFChars(env, name, NULL); - if (stream_name == NULL) { - return; /* OutOfMemoryError */ - } - printf("About to create stream: %s\n", stream_name); - pa_stream* stream = pa_stream_new(context, stream_name, &sample_spec, NULL); - assert(stream != NULL); - (*env)->ReleaseStringUTFChars(env, name, stream_name); - - pa_stream_set_state_callback(stream, stream_state_change_callback, java_context); - - setJavaPointer(env, obj, "streamPointer", stream); - printf("returning from native_open\n"); - -} - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_write - * Signature: ([BII)V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1write -(JNIEnv* env, jobject obj, jbyteArray data, jint offset, jint data_length) { - - pa_stream* stream = (pa_stream*) getJavaPointer(env, obj, "streamPointer"); - jbyte* data_buffer = (*env)->GetByteArrayElements(env, data, NULL); - jbyte* buffer_start = data_buffer + offset; - pa_stream_write(stream, buffer_start, data_length, NULL, 0, PA_SEEK_RELATIVE); - (*env)->ReleaseByteArrayElements(env, data, data_buffer, 0); - -} - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_get_writable_size - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1get_1writable_1size -(JNIEnv* env, jobject obj) { - - pa_stream *stream = (pa_stream*) getJavaPointer(env, obj, "streamPointer"); - int available = pa_stream_writable_size(stream); - -} - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_flush - * Signature: ()V - */ -JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1flush -(JNIEnv* env, jobject obj) { - - pa_stream *stream = (pa_stream*) getJavaPointer(env, obj, "streamPointer"); - pa_operation *o = pa_stream_flush(stream, NULL, NULL); - return (int) o; - -} - -JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1getOperationState(JNIEnv *env, jobject obj, jint operation) { - - return pa_operation_get_state((pa_operation *) operation); - -} - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_start - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1start -(JNIEnv *env, jobject obj) { - printf("start called\n"); - - pa_stream *stream = (pa_stream*)getJavaPointer(env, obj, "streamPointer"); - pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL); - -} - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_pause - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1pause -(JNIEnv* env, jobject obj) { - -} - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_resume - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1resume -(JNIEnv* env, jobject obj) { - -} - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_drain - * Signature: ()V - */ -JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1drain -(JNIEnv* env, jobject obj) { - pa_stream *stream = (pa_stream*) getJavaPointer(env, obj, "streamPointer"); - pa_operation *o = pa_stream_drain(stream, NULL, NULL); - return (int) o; -} - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1close -(JNIEnv* env, jobject obj) { - -} -
--- a/src/org_openjdk_sound_PulseAudioSourceDataLine.h Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include <jni.h> -/* Header for class org_openjdk_sound_PulseAudioSourceDataLine */ - -#ifndef _Included_org_openjdk_sound_PulseAudioSourceDataLine -#define _Included_org_openjdk_sound_PulseAudioSourceDataLine -#ifdef __cplusplus -extern "C" { -#endif -#undef org_openjdk_sound_PulseAudioSourceDataLine_DEFAULT_BUFFER_SIZE -#define org_openjdk_sound_PulseAudioSourceDataLine_DEFAULT_BUFFER_SIZE 1000L -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_open - * Signature: (JLjava/lang/String;Ljava/lang/String;FIIZI)V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1open - (JNIEnv *, jobject, jlong, jstring, jstring, jfloat, jint, jint, jboolean, jint); - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_write - * Signature: ([BII)V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1write - (JNIEnv *, jobject, jbyteArray, jint, jint); - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_get_writable_size - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1get_1writable_1size - (JNIEnv *, jobject); - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_getOperationState - * Signature: (I)I - */ -JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1getOperationState - (JNIEnv *, jobject, jint); - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_flush - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1flush - (JNIEnv *, jobject); - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_start - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1start - (JNIEnv *, jobject); - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_pause - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1pause - (JNIEnv *, jobject); - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_resume - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1resume - (JNIEnv *, jobject); - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_drain - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1drain - (JNIEnv *, jobject); - -/* - * Class: org_openjdk_sound_PulseAudioSourceDataLine - * Method: native_close - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1close - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif
--- a/src/org_openjdk_sound_PulseAudioStreamVolumeControl.c Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -#include <jni.h> -#include <pulse/pulseaudio.h> -#include "org_openjdk_sound_PulseAudioStreamVolumeControl.h" - -typedef struct { - pa_threaded_mainloop *mainloop; - pa_cvolume *volume; -} userdata_info; - -void *getJavaLongField(JNIEnv *env, jobject obj, char *fieldName) { - jclass cls = (*env)->GetObjectClass(env, obj); - jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "J"); - jlong value = (*env)->GetLongField(env, obj, fid); - //(*env)->DeleteLocalReference(cls); - return (void *) value; -} - -static void sink_input_change_volume(pa_context* context, - const pa_sink_input_info* sink_input_info, int eol, void* userdata) { - assert(context); - if (eol) { - return; - } - assert(sink_input_info); - - (((userdata_info *) userdata)->volume)->channels - = sink_input_info->volume.channels; - int j; - for (j = 0; j < (((userdata_info *)userdata)->volume)->channels; j++) { - (((userdata_info *)userdata)->volume)->values[j] - = sink_input_info->volume.values[j]; - } - pa_threaded_mainloop_signal(((userdata_info *) userdata)->mainloop, 0); - -} - -JNIEXPORT jfloat JNICALL Java_org_openjdk_sound_PulseAudioStreamVolumeControl_getValue(JNIEnv *env, jobject obj) { - pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); - pa_threaded_mainloop *mainloop = getJavaLongField(env, obj, "mainLoopPointer"); - pa_context *context = pa_stream_get_context(stream); - int stream_id = pa_stream_get_index(stream); - - userdata_info *userdata = malloc(sizeof(userdata_info)); - userdata->mainloop = mainloop; - userdata->volume = malloc(sizeof(pa_cvolume)); - pa_threaded_mainloop_lock(mainloop); - pa_operation *o = pa_context_get_sink_input_info((pa_context*) context ,stream_id,sink_input_change_volume, userdata); - while(pa_operation_get_state(o) != PA_OPERATION_DONE) { - pa_threaded_mainloop_wait(mainloop); - } - pa_operation_unref(o); - pa_threaded_mainloop_unlock(mainloop); - return pa_sw_volume_to_dB(userdata->volume->values[0]); - -} - -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioStreamVolumeControl_setValue (JNIEnv *env, jobject obj, jfloat new_volume) { - pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); - pa_context *context = pa_stream_get_context(stream); - int stream_id = pa_stream_get_index(stream); - int channels = pa_stream_get_sample_spec(stream)->channels; - pa_cvolume cv; - pa_context_set_sink_input_by_index(context, stream_id, pa_cvolume_set(&cv, channels, pa_sw_volume_from_dB(new_volume)), NULL, NULL); -} -
--- a/src/org_openjdk_sound_PulseAudioTargetDataLine.c Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,228 +0,0 @@ -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <jni.h> -#include <pulse/pulseaudio.h> -#include <string.h> - -#include "org_openjdk_sound_PulseAudioTargetDataLine.h" -#include "jni-common.h" - -static void stream_read_cb(pa_stream* stream, size_t length, void* userdata) { - pa_threaded_mainloop *mainloop = userdata; - pa_threaded_mainloop_signal(mainloop, 0); -} - -static void stream_operation_complete_cb(pa_stream* stream, int success, - void* userdata) { - pa_threaded_mainloop *mainloop = userdata; - pa_threaded_mainloop_signal(mainloop, 0); -} - -static void stream_state_cb(pa_stream* stream, void* userdata) { - assert(stream); - pa_threaded_mainloop *mainloop = userdata; - printf("stream state changed to %d\n", pa_stream_get_state(stream)); - switch (pa_stream_get_state(stream)) { - case PA_STREAM_READY: - case PA_STREAM_FAILED: - case PA_STREAM_TERMINATED: - pa_threaded_mainloop_signal(mainloop, 0); - break; - - default: - /* do nothing */ - break; - } -} - -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_openStream -(JNIEnv * env, jobject obj, jstring string, jfloat rate, jint size, jint channels, jboolean bigEndian, jint bufferSize) { - - printf("entering native_open\n"); - - pa_context* context = (pa_context*) contextPointer; - assert(context != NULL); - - obj = (*env)->NewGlobalRef(env, obj); - - java_context_t* java_context = malloc(sizeof(java_context)); - java_context->env = env; - java_context->obj = obj; - - //TODO: Need to deal with the buffer size. Currently ignored - - pa_sample_spec sample_spec; - - char *encoding = GetStringUTFChars(env, string, NULL); - - if( (strcmp(encoding, "PCM_UNSIGNED") == 0) && (size == 8)) { - sample_spec.format = PA_SAMPLE_U8; - } else if( (strcmp(encoding, "ALAW") == 0) && (size == 8)) { - sample_spec.format = PA_SAMPLE_ALAW; - } else if( (strcmp(encoding, "ULAW") == 0) && (size == 8)) { - sample_spec.format = PA_SAMPLE_ULAW; - } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 1)) { - sample_spec.format = PA_SAMPLE_S16BE; - } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 0)) { - sample_spec.format = PA_SAMPLE_S16LE; - } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 1)) { - sample_spec.format = PA_SAMPLE_S32BE; - } else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 0)) { - sample_spec.format = PA_SAMPLE_S32LE; - } else { - //TODO: Invalid format :throw Exception; - } - - sample_spec.rate = rate; - sample_spec.channels = channels; - - /* obtain the server from the caller */ - const jbyte* stream_name = NULL; - stream_name = (*env)->GetStringUTFChars(env, name, NULL); - if (stream_name == NULL) { - return; /* OutOfMemoryError */ - } - printf("About to create stream: %s\n", stream_name); - pa_stream* stream = pa_stream_new(context, stream_name, &sample_spec, NULL); - assert(stream != NULL); - (*env)->ReleaseStringUTFChars(env, name, stream_name); - - pa_stream_set_state_callback(stream, stream_state_change_callback, java_context); - - jclass cls = (*env)->GetObjectClass(env,obj); - jfieldID fid = (*env)->GetFieldID(env, cls, "streamPointer", "I"); - (*env)->SetIntField(env, obj, fid, (jint) stream); - - printf("returning from native_open\n"); - -} - -JNIEXPORT void JNICALL -Java_org_openjdk_sound_PulseAudioSourceDataLine_startStream(JNIEnv *env, jobject obj) { - pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); - pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); - pa_threaded_mainloop_lock(mainloop); - pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL); - pa_threaded_mainloop_wait(mainloop); - if ( pa_stream_get_state(stream) != PA_STREAM_READY ) { - printf("stream initialization failed\n"); - } - pa_threaded_mainloop_unlock(mainloop); -} - -JNIEXPORT void Java_org_openjdk_sound_PulseAudioSourceDataLine_resumeStream( - JNIEnv *env, jobject obj) { - pa_threaded_mainloop *mainloop = getJavaLongField(env, obj, - "mainLoopPointer"); - pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); - pa_threaded_mainloop_lock(mainloop); - pa_operation *o = pa_stream_cork(stream, 0, stream_operation_complete_cb, - mainloop); - while (pa_operation_get_state(o) != PA_OPERATION_DONE) { - pa_threaded_mainloop_wait(mainloop); - } - pa_operation_unref(o); - pa_threaded_mainloop_unlock(mainloop); - -} - -JNIEXPORT void Java_org_openjdk_sound_PulseAudioSourceDataLine__pauseStream( - JNIEnv *env, jobject obj) { - pa_threaded_mainloop *mainloop = getJavaLongField(env, obj, - "mainLoopPointer"); - pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); - pa_threaded_mainloop_lock(mainloop); - pa_operation *o = pa_stream_cork(stream, 1, stream_operation_complete_cb, - mainloop); - while (pa_operation_get_state(o) != PA_OPERATION_DONE) { - pa_threaded_mainloop_wait(mainloop); - } - pa_operation_unref(o); - pa_threaded_mainloop_unlock(mainloop); -} - -J - -JNIEXPORT void JNICALL -Java_org_openjdk_sound_PulseAudioSourceDataLine__closeStream(JNIEnv *env, jobject obj, jint channels, jfloat rate) { - - pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); - pa_strean_disconnect(stream); -} - -JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_available -(JNIEnv *env, jobject obj) { - pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); - pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); - pa_threaded_mainloop_lock(mainloop); - int available = pa_stream_writable_size(stream); - pa_threaded_mainloop_unlock(mainloop); - return available; -} - -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_drain -(JNIEnv *env, jobject obj) { - pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); - pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); - pa_threaded_mainloop_lock(mainloop); - pa_operation *o = pa_stream_drain(stream, stream_operation_complete_cb, mainloop); - while(pa_operation_get_state(o) != PA_OPERATION_DONE) { - pa_threaded_mainloop_wait(mainloop); - } - pa_operation_unref(o); - pa_threaded_mainloop_unlock(mainloop); -} - -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_flush -(JNIEnv *env, jobject obj) { - pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); - pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); - pa_threaded_mainloop_lock(mainloop); - pa_operation *o = pa_stream_flush(stream, stream_operation_complete_cb, mainloop); - while(pa_operation_get_state(o) != PA_OPERATION_DONE) { - pa_threaded_mainloop_wait(mainloop); - } - pa_operation_unref(o); - pa_threaded_mainloop_unlock(mainloop); -} - -JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioTargetDataLine_readFromStream -(JNIEnv * env, jobject obj, jbyteArray array, jint length, jint offset); -pa_threaded_mainloop *mainloop = getJavaLongField(env, obj, "mainLoopPointer"); -pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); -pa_threaded_mainloop_lock(mainloop); -char[length] data; -while(length> 0) { - size_t l; - while(!read_data) { - int r = pa_stream_peek(_stream, &read_data, &read_length); - if(!read_data) { - pa_threaded_mainloop_wait(mainloop); - } else { - read_index = 0; - } - } - - l = read_length < length ? read_length : length; - memcpy(data, read_data+read_index, l); - - data = data + l; - length -= l; - read_index +=l; - read_length-=l; - - if(! read_length) { - int r = pa_stream_drop(stream); - read_data = NULL; - read_length = 0; - read_index = 0; - - } - -} - -pa_threaded_mainloop_unlock(mainloop); -SetByteArrayRegion(env, array, offset, initialLength, data); -} -
--- a/src/org_openjdk_sound_PulseAudioVolumeMuteControl.c Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -void *getJavaLongField(JNIEnv *env, jobject obj, char *fieldName) { - jclass cls = (*env)->GetObjectClass(env, obj); - jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "J"); - jlong value = (*env)->GetLongField(env, obj, fid); - //(*env)->DeleteLocalReference(cls); - return (void *) value; -} - -static void sink_input_change_volume(pa_context* context, - const pa_sink_input_info* input_info, int eol, void* userdata) { - assert(context); - if (eol) { - return; - } - assert(i); - userdata = i->volume; -} - -JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioStreamVolumeControl_getValue(JNIEnv env*, jobject obj) { - pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); - int stream_id pa_stream_get_index(stream); - pa_cvolume *volume; - pa_context_get_sink_input_info((pa_context*) contextPointer ,stream_id,sink_input_change_volume, volume); - printf("%d\n", volume->values[0]); -}
--- a/src/org_openjdk_sound_PulseStreamAudioVolumeControl.c Fri Aug 01 17:16:36 2008 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ - - void *getJavaLongField(JNIEnv *env, jobject obj, char *fieldName) { - jclass cls = (*env)->GetObjectClass(env, obj); - jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "J"); - jlong value = (*env)->GetLongField(env, obj, fid); - //(*env)->DeleteLocalReference(cls); - return (void *) value; -} - -static void sink_input_change_volume(pa_context* context, const pa_sink_input_info* input_info, int eol, void* userdata) { - assert(context); - if (eol) { - return; - } - assert(i); - userdata = i->volume; -} - -JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioStreamVolumeControl_getValue(JNIEnv env*, jobject obj) { - pa_stream *stream = getJavaLongField(env, obj, "streamPointer"); - int stream_id pa_stream_get_index(stream); - pa_cvolume *volume; - pa_context_get_sink_input_info((pa_context*) contextPointer ,stream_id,sink_input_change_volume, volume); - printf("%d\n", volume->values[0]); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testsounds/COPYING Tue Aug 05 15:25:06 2008 -0400 @@ -0,0 +1,4 @@ +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
--- a/unittests/org/openjdk/sound/OtherSoundProvidersAvailableTest.java Fri Aug 01 17:16:36 2008 -0400 +++ b/unittests/org/openjdk/sound/OtherSoundProvidersAvailableTest.java Tue Aug 05 15:25:06 2008 -0400 @@ -1,3 +1,41 @@ +/* PulseAudioStreamVolumeControl.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.openjdk.sound; import javax.sound.sampled.AudioSystem;
--- a/unittests/org/openjdk/sound/PulseAudioMixerProviderTest.java Fri Aug 01 17:16:36 2008 -0400 +++ b/unittests/org/openjdk/sound/PulseAudioMixerProviderTest.java Tue Aug 05 15:25:06 2008 -0400 @@ -1,3 +1,40 @@ +/* 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.openjdk.sound; import static org.junit.Assert.*;
--- a/unittests/org/openjdk/sound/PulseAudioMixerRawTest.java Fri Aug 01 17:16:36 2008 -0400 +++ b/unittests/org/openjdk/sound/PulseAudioMixerRawTest.java Tue Aug 05 15:25:06 2008 -0400 @@ -1,8 +1,46 @@ +/* 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.openjdk.sound; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.Mixer; +import org.classpath.icedtea.pulseaudio.PulseAudioMixer; import org.junit.After; import org.junit.Before; import org.junit.Test;
--- a/unittests/org/openjdk/sound/PulseAudioMixerTest.java Fri Aug 01 17:16:36 2008 -0400 +++ b/unittests/org/openjdk/sound/PulseAudioMixerTest.java Tue Aug 05 15:25:06 2008 -0400 @@ -1,3 +1,41 @@ +/* PulseAudioStreamVolumeControl.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.openjdk.sound; @@ -15,6 +53,7 @@ import junit.framework.JUnit4TestAdapter; +import org.classpath.icedtea.pulseaudio.PulseAudioMixer; import org.junit.After; import org.junit.Before; import org.junit.Test;
--- a/unittests/org/openjdk/sound/PulseSourceDataLineTest.java Fri Aug 01 17:16:36 2008 -0400 +++ b/unittests/org/openjdk/sound/PulseSourceDataLineTest.java Tue Aug 05 15:25:06 2008 -0400 @@ -1,18 +1,67 @@ +/* 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.openjdk.sound; +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.Line; import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.UnsupportedAudioFileException; import junit.framework.JUnit4TestAdapter; +import org.classpath.icedtea.pulseaudio.PulseAudioMixer; +import org.classpath.icedtea.pulseaudio.PulseAudioSourceDataLine; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.junit.Assert; public class PulseSourceDataLineTest { - + Mixer mixer; + SourceDataLine line; public static junit.framework.Test suite() { return new JUnit4TestAdapter(PulseSourceDataLineTest.class); @@ -20,20 +69,65 @@ @Before public void setUp() throws Exception { - + mixer = PulseAudioMixer.getInstance(); + mixer.open(); + line = (PulseAudioSourceDataLine) mixer.getLine(new Line.Info(PulseAudioSourceDataLine.class)); + Assert.assertNotNull(line); } @Test - public void testAcquiringSourceDataLine() throws LineUnavailableException { - PulseAudioMixer mixer = PulseAudioMixer.getInstance(); - mixer.open(); - PulseAudioSourceDataLine line = (PulseAudioSourceDataLine) mixer.getLine(new Line.Info(PulseAudioSourceDataLine.class)); - Assert.assertNotNull(line); + public void testPlay() throws LineUnavailableException, UnsupportedAudioFileException, IOException { + File soundFile = new File("new.wav"); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(soundFile); + AudioFormat audioFormat = audioInputStream.getFormat(); + 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); + } + } + + line.flush(); + line.close(); + } + @Test + public void testPlayLoud() throws UnsupportedAudioFileException, IOException, LineUnavailableException { + File soundFile = new File("new.wav"); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(soundFile); + AudioFormat audioFormat = audioInputStream.getFormat(); + 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); + } + } + + line.flush(); + line.close(); + + } + @After public void tearDown() throws Exception { + + mixer.close(); } }