1 /* 2 * Copyright (c) 2009-2010 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 package com.jme3.audio; 34 35 import com.jme3.util.NativeObject; 36 import java.io.Closeable; 37 import java.io.IOException; 38 import java.io.InputStream; 39 import java.util.logging.Level; 40 import java.util.logging.Logger; 41 42 /** 43 * <code>AudioStream</code> is an implementation of AudioData that 44 * acquires the audio from an InputStream. Audio can be streamed 45 * from network, hard drive etc. It is assumed the data coming 46 * from the input stream is uncompressed. 47 * 48 * @author Kirill Vainer 49 */ 50 public class AudioStream extends AudioData implements Closeable{ 51 52 private final static Logger logger = Logger.getLogger(AudioStream.class.getName()); 53 protected InputStream in; 54 protected float duration = -1f; 55 protected boolean open = false; 56 protected int[] ids; 57 AudioStream()58 public AudioStream(){ 59 super(); 60 } 61 AudioStream(int[] ids)62 protected AudioStream(int[] ids){ 63 // Pass some dummy ID so handle 64 // doesn't get created. 65 super(-1); 66 // This is what gets destroyed in reality 67 this.ids = ids; 68 } 69 updateData(InputStream in, float duration)70 public void updateData(InputStream in, float duration){ 71 if (id != -1 || this.in != null) 72 throw new IllegalStateException("Data already set!"); 73 74 this.in = in; 75 this.duration = duration; 76 open = true; 77 } 78 79 /** 80 * Reads samples from the stream. The format of the data 81 * depends on the getSampleRate(), getChannels(), getBitsPerSample() 82 * values. 83 * 84 * @param buf Buffer where to read the samples 85 * @param offset The offset in the buffer where to read samples 86 * @param length The length inside the buffer where to read samples 87 * @return number of bytes read. 88 */ readSamples(byte[] buf, int offset, int length)89 public int readSamples(byte[] buf, int offset, int length){ 90 if (!open) 91 return -1; 92 93 try{ 94 return in.read(buf, offset, length); 95 }catch (IOException ex){ 96 return -1; 97 } 98 } 99 100 /** 101 * Reads samples from the stream. 102 * 103 * @see AudioStream#readSamples(byte[], int, int) 104 * @param buf Buffer where to read the samples 105 * @return number of bytes read. 106 */ readSamples(byte[] buf)107 public int readSamples(byte[] buf){ 108 return readSamples(buf, 0, buf.length); 109 } 110 getDuration()111 public float getDuration(){ 112 return duration; 113 } 114 115 @Override getId()116 public int getId(){ 117 throw new RuntimeException("Don't use getId() on streams"); 118 } 119 120 @Override setId(int id)121 public void setId(int id){ 122 throw new RuntimeException("Don't use setId() on streams"); 123 } 124 initIds(int count)125 public void initIds(int count){ 126 ids = new int[count]; 127 } 128 getId(int index)129 public int getId(int index){ 130 return ids[index]; 131 } 132 setId(int index, int id)133 public void setId(int index, int id){ 134 ids[index] = id; 135 } 136 getIds()137 public int[] getIds(){ 138 return ids; 139 } 140 setIds(int[] ids)141 public void setIds(int[] ids){ 142 this.ids = ids; 143 } 144 145 @Override getDataType()146 public DataType getDataType() { 147 return DataType.Stream; 148 } 149 150 @Override resetObject()151 public void resetObject() { 152 id = -1; 153 ids = null; 154 setUpdateNeeded(); 155 } 156 157 @Override deleteObject(Object rendererObject)158 public void deleteObject(Object rendererObject) { 159 // It seems that the audio renderer is already doing a good 160 // job at deleting audio streams when they finish playing. 161 // ((AudioRenderer)rendererObject).deleteAudioData(this); 162 } 163 164 @Override createDestructableClone()165 public NativeObject createDestructableClone() { 166 return new AudioStream(ids); 167 } 168 169 /** 170 * @return Whether the stream is open or not. Reading from a closed 171 * stream will always return eof. 172 */ isOpen()173 public boolean isOpen(){ 174 return open; 175 } 176 177 /** 178 * Closes the stream, releasing all data relating to it. Reading 179 * from the stream will return eof. 180 * @throws IOException 181 */ close()182 public void close() { 183 if (in != null && open){ 184 try{ 185 in.close(); 186 }catch (IOException ex){ 187 } 188 open = false; 189 }else{ 190 throw new RuntimeException("AudioStream is already closed!"); 191 } 192 } 193 194 setTime(float time)195 public void setTime(float time){ 196 if(in instanceof SeekableStream){ 197 ((SeekableStream)in).setTime(time); 198 }else{ 199 logger.log(Level.WARNING,"Cannot use setTime on a stream that is not seekable. You must load the file with the streamCache option set to true"); 200 } 201 } 202 203 204 } 205