001: /* AAudio.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Wed Nov 16 15:15:40 2005, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2005 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.sound;
020:
021: import java.io.File;
022: import java.io.InputStream;
023: import java.io.FileInputStream;
024: import java.io.ByteArrayInputStream;
025: import java.io.Reader;
026: import java.io.IOException;
027: import java.net.URL;
028:
029: import javax.sound.sampled.AudioSystem;
030: import javax.sound.sampled.UnsupportedAudioFileException;
031:
032: import org.zkoss.lang.SystemException;
033: import org.zkoss.util.media.ContentTypes;
034: import org.zkoss.io.NullInputStream;
035:
036: /**
037: * Represents an audio.
038: * Unlike javax.sound.AudioClip, this class is used only to hold the raw
039: * data as opaque rather than manilupate the sound.
040: *
041: * <p>In other words, it is used to retrieve and store the opaque data
042: * as polymorphic thru the {@link org.zkoss.util.media.Media} interface.
043: *
044: * @author tomyeh
045: */
046: public class AAudio implements Audio {
047: /** Used if you want to implement a meida whose input stream is created
048: * dynamically each time {@link #getStreamData} is called.
049: * @see #AAudio(String,,InputStream)
050: */
051: protected static final InputStream DYNAMIC_STREAM = new NullInputStream();
052:
053: /** The raw data in byte array.
054: * Exactly one of {@link #_data} and {@link #_isdata} is not null.
055: */
056: private final byte[] _data;
057: /** The raw data in stream (or {@link #DYNAMIC_STREAM}).
058: * Exactly one of {@link #_data} and {@link #_isdata} is not null.
059: */
060: private final InputStream _isdata;
061: /** The URL of the data.
062: */
063: private final URL _url;
064: /** The file of the data.
065: */
066: private final File _file;
067:
068: /** The format name, e.g., "jpeg", "gif" and "png". */
069: private final String _format;
070: /** The content type. */
071: private final String _ctype;
072: /** The name (usually filename). */
073: private final String _name;
074:
075: public AAudio(String name, byte[] data) throws IOException {
076: if (data == null)
077: throw new IllegalArgumentException("null data");
078: _name = name;
079: _data = data;
080: _isdata = null;
081: _url = null;
082: _file = null;
083:
084: String format = null;
085: try {
086: format = AudioSystem.getAudioFileFormat(
087: new ByteArrayInputStream(data)).getType()
088: .getExtension();
089: } catch (UnsupportedAudioFileException ex) {
090: format = getFormatByName(_name);
091: if (format == null)
092: throw (IOException) new IOException().initCause(ex);
093: }
094: _format = format;
095: _ctype = getContentType(_format);
096: }
097:
098: /**
099: * Creates an instance of an audio with an input stream.
100: * If the stream shall be created each time {@link #getStreamData} is called,
101: * you can pass {@link #DYNAMIC_STREAM} to the dat argument, and then
102: * override {@link #getStreamData}.
103: *
104: * <p>Note: the caller of {@link #getStreamData} has to close
105: * the returned input stream.
106: */
107: public AAudio(String name, InputStream isdata) throws IOException {
108: if (isdata == null)
109: throw new IllegalArgumentException("null stream");
110: _name = name;
111: _isdata = isdata;
112: _data = null;
113: _url = null;
114: _file = null;
115:
116: String format = null;
117: try {
118: format = AudioSystem
119: .getAudioFileFormat(
120: isdata == DYNAMIC_STREAM ? getStreamData()
121: : isdata).getType().getExtension();
122: } catch (UnsupportedAudioFileException ex) {
123: format = getFormatByName(_name);
124: if (format == null)
125: throw (IOException) new IOException().initCause(ex);
126: }
127: _format = format;
128: _ctype = getContentType(_format);
129: }
130:
131: /** Constructs an audio with an URL.
132: */
133: public AAudio(URL url) throws IOException {
134: if (url == null)
135: throw new IllegalArgumentException("null url");
136: _name = getName(url);
137: _url = url;
138: _isdata = DYNAMIC_STREAM;
139: _data = null;
140: _file = null;
141:
142: String format = null;
143: try {
144: format = AudioSystem.getAudioFileFormat(url).getType()
145: .getExtension();
146: } catch (UnsupportedAudioFileException ex) {
147: format = getFormatByName(_name);
148: if (format == null)
149: throw (IOException) new IOException().initCause(ex);
150: }
151: _format = format;
152: _ctype = getContentType(_format);
153: }
154:
155: /** Constructs an audio with a file.
156: */
157: public AAudio(File file) throws IOException {
158: if (file == null)
159: throw new IllegalArgumentException("null url");
160: _name = file.getName();
161: _file = file;
162: _isdata = DYNAMIC_STREAM;
163: _data = null;
164: _url = null;
165:
166: String format = null;
167: try {
168: format = AudioSystem.getAudioFileFormat(file).getType()
169: .getExtension();
170: } catch (UnsupportedAudioFileException ex) {
171: format = getFormatByName(_name);
172: if (format == null)
173: throw (IOException) new IOException().initCause(ex);
174: }
175: _format = format;
176: _ctype = getContentType(_format);
177: }
178:
179: /** Constructs an audio with a file name.
180: */
181: public AAudio(String filename) throws IOException {
182: this (new File(filename));
183: }
184:
185: /**
186: * Creates an instance of an audio with an input stream.
187: * If the stream shall be created each time {@link #getStreamData} is called,
188: * you can pass {@link #DYNAMIC_STREAM} to the dat argument, and then
189: * override {@link #getStreamData}.
190: *
191: * <p>Note: the caller of {@link #getStreamData} has to close
192: * the returned input stream.
193: */
194: public AAudio(InputStream is) throws IOException {
195: this (null, is);
196: }
197:
198: private static String getName(URL url) {
199: String name = url.getPath();
200: if (name != null) {
201: {
202: final int j = name.lastIndexOf(File.pathSeparatorChar);
203: if (j >= 0)
204: name = name.substring(j + 1);
205: }
206: if (File.pathSeparatorChar != '/') {
207: final int j = name.lastIndexOf('/');
208: if (j >= 0)
209: name = name.substring(j + 1);
210: }
211: }
212: return name;
213: }
214:
215: private static String getContentType(String format) {
216: final String ctype = ContentTypes.getContentType(format);
217: return ctype != null ? ctype : "audio/" + format;
218: }
219:
220: private static String getFormatByName(String name) {
221: if (name != null) {
222: final int j = name.lastIndexOf('.') + 1, k = name
223: .lastIndexOf('/') + 1;
224: if (j > k && j < name.length())
225: return name.substring(j);
226: }
227: return null;
228: }
229:
230: //-- Media --//
231: public final boolean isBinary() {
232: return true;
233: }
234:
235: public final boolean inMemory() {
236: return _data != null;
237: }
238:
239: public byte[] getByteData() {
240: if (_data == null)
241: throw new IllegalStateException(
242: "Use getStreamData() instead");
243: return _data;
244: }
245:
246: /** Always throws IllegalStateException.
247: */
248: public final String getStringData() {
249: throw newIllegalStateException();
250: }
251:
252: /** Returns the data in the input stream.
253: *
254: * <p>Note: the caller has to invoke {@link InputStream#close}
255: * after using the input stream returned by {@link #getStreamData}.
256: */
257: public InputStream getStreamData() {
258: try {
259: if (_url != null)
260: return _url.openStream();
261: if (_file != null)
262: return new FileInputStream(_file);
263: } catch (java.io.IOException ex) {
264: throw new SystemException("Unable to read "
265: + (_url != null ? _url.toString() : _file
266: .toString()), ex);
267: }
268: if (_isdata != null)
269: return _isdata;
270: return new ByteArrayInputStream(_data);
271: }
272:
273: /** Not supported. It always throws IllegalStateException.
274: */
275: public final Reader getReaderData() {
276: throw newIllegalStateException();
277: }
278:
279: private final IllegalStateException newIllegalStateException() {
280: return new IllegalStateException(
281: _isdata != null ? "Use getStreamData() instead"
282: : "Use getByteData() instead");
283: }
284:
285: public final String getName() {
286: return _name;
287: }
288:
289: public final String getFormat() {
290: return _format;
291: }
292:
293: public final String getContentType() {
294: return _ctype;
295: }
296: }
|