diff options
-rw-r--r-- | src/java/demos/devmaster/lesson8/OggStreamer.java | 99 | ||||
-rw-r--r-- | www/devmaster/lesson8.html | 47 |
2 files changed, 121 insertions, 25 deletions
diff --git a/src/java/demos/devmaster/lesson8/OggStreamer.java b/src/java/demos/devmaster/lesson8/OggStreamer.java index 1f52973..a7b9b45 100644 --- a/src/java/demos/devmaster/lesson8/OggStreamer.java +++ b/src/java/demos/devmaster/lesson8/OggStreamer.java @@ -68,13 +68,23 @@ public class OggStreamer { } } + private static boolean debug = false; + private static int totalBytes = 0; + + private static void debugMsg(String str) { + if (debug) System.err.println(str); + } + private OggDecoder oggDecoder; // The size of a chunk from the stream that we want to read for each update. - private static int BUFFER_SIZE = 4096*8; + private static int BUFFER_SIZE = 4096*16; + + // The number of buffers used in the audio pipeline + private static int NUM_BUFFERS = 2; - // Buffers hold sound data. There are two of them (front/back) - private int[] buffers = new int[2]; + // Buffers hold sound data. There are two of them by default (front/back) + private int[] buffers = new int[NUM_BUFFERS]; // Sources are points emitting sound. private int[] source = new int[1]; @@ -89,6 +99,8 @@ public class OggStreamer { private URL url; + private long sleepTime = 0; + /** Creates a new instance of OggStreamer */ public OggStreamer(URL url) { this.url = url; @@ -106,20 +118,35 @@ public class OggStreamer { return false; } - if (oggDecoder.numChannels() == 1) + int numChannels = oggDecoder.numChannels(); + int numBytesPerSample = 2; + + if (numChannels == 1) format = AL.AL_FORMAT_MONO16; else format = AL.AL_FORMAT_STEREO16; rate = oggDecoder.sampleRate(); - System.err.println("format = 0x" + Integer.toString(format, 16)); + // A rough estimation of how much time in milliseconds we can sleep + // before checking to see if the queued buffers have been played + // (so that we dont peg the CPU by doing an active wait). We divide + // by 10 at the end to be safe... + // round it off to the nearest multiple of 10. + sleepTime = (long)(1000.0 * BUFFER_SIZE / + numBytesPerSample / numChannels / rate / 10.0); + sleepTime = (sleepTime + 10)/10 * 10; + + System.err.println("#Buffers: " + NUM_BUFFERS); + System.err.println("Buffer size: " + BUFFER_SIZE); + System.err.println("Format: 0x" + Integer.toString(format, 16)); + System.err.println("Sleep time: " + sleepTime); // 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); - al.alGenBuffers(2, buffers, 0); check(); + al.alGenBuffers(NUM_BUFFERS, buffers, 0); check(); al.alGenSources(1, source, 0); check(); al.alSourcefv(source[0], AL.AL_POSITION , sourcePos, 0); @@ -142,8 +169,9 @@ public class OggStreamer { al.alSourceStop(source[0]); empty(); - al.alDeleteSources(1, source, 0); check(); - al.alDeleteBuffers(2, buffers, 0); check(); + for (int i = 0; i < NUM_BUFFERS; i++) { + al.alDeleteSources(i, source, 0); check(); + } } /** @@ -153,13 +181,14 @@ public class OggStreamer { if (playing()) return true; - if (!stream(buffers[0])) - return false; - - if(!stream(buffers[1])) - return false; + debugMsg("playback(): stream all buffers"); + for (int i = 0; i < NUM_BUFFERS; i++) { + if (!stream(buffers[i])) + return false; + } - al.alSourceQueueBuffers(source[0], 2, buffers, 0); + debugMsg("playback(): queue all buffers & play source"); + al.alSourceQueueBuffers(source[0], NUM_BUFFERS, buffers, 0); al.alSourcePlay(source[0]); return true; @@ -183,6 +212,7 @@ public class OggStreamer { int[] processed = new int[1]; boolean active = true; + debugMsg("update()"); al.alGetSourcei(source[0], AL.AL_BUFFERS_PROCESSED, processed, 0); while (processed[0] > 0) @@ -190,9 +220,11 @@ public class OggStreamer { int[] buffer = new int[1]; al.alSourceUnqueueBuffers(source[0], 1, buffer, 0); check(); + debugMsg("update(): buffer unqueued => " + buffer[0]); active = stream(buffer[0]); + debugMsg("update(): buffer queued => " + buffer[0]); al.alSourceQueueBuffers(source[0], 1, buffer, 0); check(); processed[0]--; @@ -216,6 +248,9 @@ public class OggStreamer { return false; } + totalBytes += size; + debugMsg("stream(): buffer data => " + buffer + " totalBytes:" + totalBytes); + ByteBuffer data = ByteBuffer.wrap(pcm, 0, size); al.alBufferData(buffer, format, data, size, rate); check(); @@ -265,6 +300,14 @@ public class OggStreamer { return false; while (update()) { + // We will try sleeping for sometime so that we dont + // peg the CPU... + try { + Thread.sleep(sleepTime); + } catch (Exception e) { + e.printStackTrace(); + } + if (playing()) continue; if (!playback()) @@ -284,12 +327,23 @@ public class OggStreamer { URL url; try { - if (args.length == 0) { - url = OggStreamer.class.getClassLoader().getResource("demos/data/broken_glass.ogg"); - (new OggStreamer(url)).playstream(); - } - + boolean played = false; for (int i = 0; i < args.length; i++) { + if ("-bs".equals(args[i])) { + BUFFER_SIZE = Integer.valueOf(args[++i]).intValue(); + continue; + } + + if ("-nb".equals(args[i])) { + NUM_BUFFERS = Integer.valueOf(args[++i]).intValue(); + continue; + } + + if ("-d".equals(args[i])) { + debug = true; + continue; + } + System.err.println("Playing Ogg stream : " + args[i]); url = ((new File(args[i])).exists()) ? @@ -297,8 +351,15 @@ public class OggStreamer { if ((new OggStreamer(url)).playstream()) continue; + played = true; System.err.println("ERROR!!"); } + + if (!played) { + url = OggStreamer.class.getClassLoader().getResource("demos/data/broken_glass.ogg"); + (new OggStreamer(url)).playstream(); + } + } catch (Exception e) { e.printStackTrace(); } diff --git a/www/devmaster/lesson8.html b/www/devmaster/lesson8.html index 4d68908..a091df1 100644 --- a/www/devmaster/lesson8.html +++ b/www/devmaster/lesson8.html @@ -135,7 +135,13 @@ tutorial. <var>OggStreamer</var> which is the main class doing most of the worki </p> -<pre class="code"> // The size of a chunk from the stream that we want to read for each update.<br> private static int BUFFER_SIZE = 4096*8;<br></pre> +<pre class="code"> + // The size of a chunk from the stream that we want to read for each update. + private static int BUFFER_SIZE = 4096*8; + + // The number of buffers used in the audio pipeline + private static int NUM_BUFFERS = 2; +</pre> @@ -170,8 +176,13 @@ just yet. I believe my comments should give you an idea of what they're for.</p> -<pre class="code"> // Buffers hold sound data. There are two of them (front/back)<br> private int[] buffers = new int[2];<br> <br> // Sources are points emitting sound.<br> private int[] source = new int[1];<br> <br> private int format; // OpenAL data format<br> private int rate; // sample rate<br></pre> - +<pre class="code"> + // Buffers hold sound data. There are two of them by default (front/back) + private int[] buffers = new int[NUM_BUFFERS]; + + // Sources are points emitting sound. + private int[] source = new int[1]; +</pre> <p>First thing that I want to point out is that we have 2 buffers dedicated to @@ -197,7 +208,7 @@ enumerator based on how many channels are in the Ogg and then make a not of the -<pre class="code"> public boolean open() {<br> ...<br><br> al.alGenBuffers(2, buffers, 0); check();<br> al.alGenSources(1, source, 0); check();<br><br> al.alSourcefv(source[0], AL.AL_POSITION , sourcePos, 0);<br> al.alSourcefv(source[0], AL.AL_VELOCITY , sourceVel, 0);<br> al.alSourcefv(source[0], AL.AL_DIRECTION, sourceDir, 0);<br> <br> al.alSourcef(source[0], AL.AL_ROLLOFF_FACTOR, 0.0f );<br> al.alSourcei(source[0], AL.AL_SOURCE_RELATIVE, AL.AL_TRUE);<br><br> ...<br> }<br></pre> +<pre class="code"> public boolean open() {<br> ...<br><br> al.alGenBuffers(NUM_BUFFERS, buffers, 0); check();<br> al.alGenSources(1, source, 0); check();<br><br> al.alSourcefv(source[0], AL.AL_POSITION , sourcePos, 0);<br> al.alSourcefv(source[0], AL.AL_VELOCITY , sourceVel, 0);<br> al.alSourcefv(source[0], AL.AL_DIRECTION, sourceDir, 0);<br> <br> al.alSourcef(source[0], AL.AL_ROLLOFF_FACTOR, 0.0f );<br> al.alSourcei(source[0], AL.AL_SOURCE_RELATIVE, AL.AL_TRUE);<br><br> ...<br> }<br></pre> @@ -211,7 +222,16 @@ will still hear it. The same idea applies to source relativity.</p> -<pre class="code"> public void release() {<br> al.alSourceStop(source[0]);<br> empty();<br><br> al.alDeleteSources(1, source, 0); check();<br> al.alDeleteBuffers(2, buffers, 0); check();<br> }<br></pre> +<pre class="code"> + public void release() { + al.alSourceStop(source[0]); + empty(); + + for (int i = 0; i < NUM_BUFFERS; i++) { + al.alDeleteSources(i, source, 0); check(); + } + } +</pre> <p>We can clean up after ourselves using this. We stop the source, empty out any @@ -219,7 +239,22 @@ buffers that are still in the queue, and destroy our objects. </p> -<pre class="code"> public boolean playback() {<br> if (playing())<br> return true;<br> <br> if (!stream(buffers[0]))<br> return false;<br> <br> if(!stream(buffers[1]))<br> return false;<br> <br> al.alSourceQueueBuffers(source[0], 2, buffers, 0);<br> al.alSourcePlay(source[0]);<br> <br> return true;<br> }<br></pre> +<pre class="code"> + public boolean playback() { + if (playing()) + return true; + + for (int i = 0; i < NUM_BUFFERS; i++) { + if (!stream(buffers[i])) + return false; + } + + al.alSourceQueueBuffers(source[0], NUM_BUFFERS, buffers, 0); + al.alSourcePlay(source[0]); + + return true; + } +</pre> |