diff options
Diffstat (limited to 'src/java/demos/devmaster/lesson8/OggStreamer.java')
-rw-r--r-- | src/java/demos/devmaster/lesson8/OggStreamer.java | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/src/java/demos/devmaster/lesson8/OggStreamer.java b/src/java/demos/devmaster/lesson8/OggStreamer.java new file mode 100644 index 0000000..4858f23 --- /dev/null +++ b/src/java/demos/devmaster/lesson8/OggStreamer.java @@ -0,0 +1,262 @@ +/** + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * -Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR + * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS + * LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A + * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT + * OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS + * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in the + * design, construction, operation or maintenance of any nuclear facility. + * + */ + +package demos.devmaster.lesson8; + +import java.io.File; +import java.net.URL; +import java.nio.ByteBuffer; +import java.util.Arrays; +import net.java.games.joal.AL; +import net.java.games.joal.ALException; +import net.java.games.joal.ALFactory; +import net.java.games.joal.util.ALut; +/** + * + * This is a translation of the OggVorbis streamer OpenAL tutorial + * at http://www.devmaster.net/articles/openal-tutorials/lesson8.php + * + * It uses the Java Ogg library from http://www.j-ogg.de to do the Ogg + * file decoding... + * + * @author Krishna K Gadepalli + */ +public class OggStreamer { + + OggDecoder oggDecoder; + + static AL al = null; + static int BUFFER_SIZE = 4096*4; + + static { + // Initialize OpenAL and clear the error bit. + try { + ALut.alutInit(); + al = ALFactory.getAL(); + al.alGetError(); + } catch (ALException e) { + System.err.println("Error initializing OpenAL"); + e.printStackTrace(); + } + } + + // Buffers hold sound data. + private int[] buffers = new int[2]; + + // Sources are points emitting sound. + private int[] source = new int[1]; + + // Position, Velocity, Direction of the source sound. + private float[] sourcePos = { 0.0f, 0.0f, 0.0f }; + private float[] sourceVel = { 0.0f, 0.0f, 0.0f }; + private float[] sourceDir = { 0.0f, 0.0f, 0.0f }; + + private int format; // OpenAL data format + private int rate; // sample rate + + /** Creates a new instance of OggStreamer */ + public OggStreamer(URL url) { + this.oggDecoder = new OggDecoder(url); + } + + public boolean open() { + if (!oggDecoder.initialize()) { + System.err.println("Error initializing ogg stream..."); + return false; + } + + // TODO: I am not if this is the right way to fix the endian + // problems I am having... but this seems to fix it on Linux + oggDecoder.setSwap(true); + + switch (oggDecoder.numChannels()) { + case 1: format = AL.AL_FORMAT_MONO16; break; + case 2: format = AL.AL_FORMAT_STEREO16; break; + default: + System.err.println("Incorrect number of channels.."); + return false; + } + + rate = oggDecoder.sampleRate(); + + al.alGenBuffers(2, buffers, 0); check(); + al.alGenSources(1, source, 0); check(); + + System.err.println("format = 0x" + Integer.toString(format, 16)); + // System.err.println("buffers = " + Arrays.toString(buffers)); + // System.err.println("source = " + Arrays.toString(source )); + + al.alSourcefv(source[0], AL.AL_POSITION , sourcePos, 0); + al.alSourcefv(source[0], AL.AL_VELOCITY , sourceVel, 0); + al.alSourcefv(source[0], AL.AL_DIRECTION, sourceDir, 0); + + al.alSourcef(source[0], AL.AL_ROLLOFF_FACTOR, 0.0f ); + al.alSourcei(source[0], AL.AL_SOURCE_RELATIVE, AL.AL_TRUE); + + return true; + } + + public void release() { + al.alSourceStop(source[0]); + empty(); + + al.alDeleteSources(1, source, 0); check(); + al.alDeleteBuffers(2, buffers, 0); check(); + + // ov_clear(&oggStream); + } + + public boolean playback() { + if (playing()) + return true; + + if (!stream(buffers[0])) + return false; + + if(!stream(buffers[1])) + return false; + + al.alSourceQueueBuffers(source[0], 2, buffers, 0); + al.alSourcePlay(source[0]); + + return true; + } + + public boolean playing() { + int[] state = new int[1]; + + al.alGetSourcei(source[0], AL.AL_SOURCE_STATE, state, 0); + + return (state[0] == AL.AL_PLAYING); + } + + public boolean update() { + int[] processed = new int[1]; + boolean active = true; + + al.alGetSourcei(source[0], AL.AL_BUFFERS_PROCESSED, processed, 0); + + while (processed[0] > 0) + { + int[] buffer = new int[1]; + + al.alSourceUnqueueBuffers(source[0], 1, buffer, 0); check(); + + active = stream(buffer[0]); + + al.alSourceQueueBuffers(source[0], 1, buffer, 0); check(); + + processed[0]--; + } + + return active; + } + + public boolean stream(int buffer) { + byte[] pcm = new byte[BUFFER_SIZE]; + int size = 0; + + try { + if ((size = oggDecoder.read(pcm)) <= 0) + return false; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + ByteBuffer data = ByteBuffer.wrap(pcm, 0, size); + al.alBufferData(buffer, format, data, size, rate); + check(); + + return true; + } + + public void empty() { + } + + private void check() { + if (al.alGetError() != AL.AL_NO_ERROR) + throw new ALException("OpenAL error raised..."); + } + + public boolean play() { + if (!open()) + return false; + + oggDecoder.dump(); + + if (!playback()) + return false; + + while (update()) { + if (playing()) continue; + + if (!playback()) + return false; + } + + return true; + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + if (al == null) + return; + + URL url; + + try { + if (args.length == 0) { + url = OggStreamer.class.getClassLoader().getResource("demos/data/crickets.ogg"); + (new OggStreamer(url)).play(); + } + + for (int i = 0; i < args.length; i++) { + System.err.println("Playing Ogg stream : " + args[i]); + + url = ((new File(args[i])).exists()) ? + new URL("file:" + args[i]) : new URL(args[i]); + + if ((new OggStreamer(url)).play()) continue; + + System.err.println("ERROR!!"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} |