001: /*
002: * @(#)J3DLiveAudioRenderer.java 1.0, 1 May 2000
003: *
004: * Copyright (c) 2000 Silvere Martin-Michiellot All Rights Reserved.
005: *
006: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
007: * royalty free, license to use, modify and redistribute this
008: * software in source and binary code form,
009: * provided that i) this copyright notice and license appear on all copies of
010: * the software; and ii) Licensee does not utilize the software in a manner
011: * which is disparaging to Silvere Martin-Michiellot.
012: *
013: * This software is provided "AS IS," without a warranty of any kind. ALL
014: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
015: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
016: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. Silvere Martin-Michiellot
017: * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
018: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
019: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
020: * Silvere Martin-Michiellot OR ITS LICENSORS BE LIABLE
021: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
022: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
023: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
024: * OR INABILITY TO USE SOFTWARE, EVEN IF Silvere Martin-Michiellot HAS BEEN
025: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
026: *
027: * This software is not designed or intended for use in on-line control of
028: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
029: * the design, construction, operation or maintenance of any nuclear
030: * facility. Licensee represents and warrants that it will not use or
031: * redistribute the Software for such purposes.
032: *
033: * @Author: Silvere Martin-Michiellot
034: *
035: */
036:
037: package com.db.media.in;
038:
039: import java.io.IOException;
040: import java.io.ByteArrayInputStream;
041: import java.util.Vector;
042: import javax.media.*;
043: import javax.media.control.*;
044: import javax.media.format.*;
045: import javax.media.protocol.*;
046: import javax.media.j3d.MediaContainer;
047:
048: import javax.media.j3d.Sound;
049:
050: public class J3DLiveAudioRenderer implements ControllerListener,
051: Renderer {
052:
053: //Capture Microphone and store audio data in an InputStream to be used by a Java3D MediaContainer
054:
055: /*************************************************************************
056: * Variables and Constants
057: *************************************************************************/
058:
059: int[] waitSync = new int[0];
060: boolean stateTransOK = true;
061:
062: public static final boolean DEBUG = false;
063:
064: // The descriptive name of this renderer
065: private static final String name = "J3DLiveAudioRenderer";
066:
067: private AudioFormat inputFormat;
068: private AudioFormat supportedAudioFormat;
069: private Format[] supportedAudioFormats;
070:
071: private Processor processor;
072: private Sound sound;
073: private StateHelper stateHelper;
074: private DataSink dataSink;
075:
076: int count = 0;
077: boolean firstFrame;
078:
079: boolean byRef = true;
080:
081: //sound must not be null
082: public J3DLiveAudioRenderer(Sound sound) {
083:
084: CaptureDeviceInfo captureDeviceInfo;
085: MediaLocator mediaLocator;
086: DataSource dataSource;
087:
088: this .sound = sound;
089:
090: // Get the CaptureDeviceInfo for the live audio capture device
091: Vector deviceList = CaptureDeviceManager
092: .getDeviceList(new AudioFormat(AudioFormat.LINEAR,
093: 44100, 16, 2));
094:
095: if (deviceList.size() > 0) {
096:
097: captureDeviceInfo = (CaptureDeviceInfo) deviceList
098: .firstElement();
099: // Create a Player for the capture device:
100: try {
101:
102: processor = Manager.createProcessor(captureDeviceInfo
103: .getLocator());
104: stateHelper = new StateHelper(processor);
105: // Configure the processor
106: if (!stateHelper.configure(10000))
107: System.exit(-1);
108:
109: // use processor as a player
110: processor.setContentDescriptor(null);
111:
112: if (!stateHelper.realize(10000))
113: System.exit(-1);
114:
115: // if the Processor implements StreamWriterControl, we can
116: // call setStreamSizeLimit
117: // to set a limit on the size of the file that is written.
118: StreamWriterControl streamWriterControl = (StreamWriterControl) processor
119: .getControl("javax.media.control.StreamWriterControl");
120: //set limit to 5MB
121: if (streamWriterControl != null)
122: streamWriterControl.setStreamSizeLimit(5000000);
123:
124: //stateHelper.prefetch();
125:
126: // now start the filewriter and processor
127: // Capture for 5 seconds
128: stateHelper.playToEndOfMedia(5000);
129:
130: } catch (IOException e) {
131:
132: System.exit(-1);
133:
134: } catch (NoProcessorException e) {
135:
136: System.exit(-1);
137:
138: }
139:
140: }
141:
142: else {
143: // Exit if we can't find a device that does linear, 44100Hz, 16 bit, stereo audio.
144: if (DEBUG) {
145: System.out.println("failed to find a microphone.");
146: }
147: System.exit(-1);
148: }
149:
150: }
151:
152: /****************************************************************
153: * Controls implementation
154: ****************************************************************/
155:
156: /**
157: * Returns an array of supported controls
158: **/
159: public Object[] getControls() {
160: // No controls
161: return (Object[]) new Control[0];
162: }
163:
164: /**
165: * Return the control based on a control type for the PlugIn.
166: */
167: public Object getControl(String controlType) {
168: try {
169: Class cls = Class.forName(controlType);
170: Object cs[] = getControls();
171: for (int i = 0; i < cs.length; i++) {
172: if (cls.isInstance(cs[i]))
173: return cs[i];
174: }
175: return null;
176: } catch (Exception e) { // no such controlType or such control
177: return null;
178: }
179: }
180:
181: /*************************************************************************
182: * PlugIn implementation
183: *************************************************************************/
184:
185: public String getName() {
186: return name;
187: }
188:
189: /**
190: * Opens the plugin
191: */
192: public void open() throws ResourceUnavailableException {
193:
194: firstFrame = true;
195: count = 0;
196:
197: }
198:
199: /**
200: * Resets the state of the plug-in. Typically at end of media or when media
201: * is repositioned.
202: */
203: public void reset() {
204: // Capture for 5 seconds
205: stateHelper.playToEndOfMedia(5000);
206: }
207:
208: public synchronized void close() {
209:
210: stateHelper.close();
211:
212: }
213:
214: /*************************************************************************
215: * Renderer implementation
216: *************************************************************************/
217:
218: public void start() {
219:
220: }
221:
222: public void stop() {
223:
224: }
225:
226: /**
227: * Lists the possible input formats supported by this plug-in.
228: */
229: public Format[] getSupportedInputFormats() {
230: return supportedAudioFormats;
231: }
232:
233: /**
234: * Set the data input format.
235: */
236: public Format setInputFormat(Format format) {
237: if (format != null && format instanceof AudioFormat
238: && format.matches(supportedAudioFormat)) {
239:
240: inputFormat = (AudioFormat) format;
241: return format;
242: } else
243: return null;
244: }
245:
246: /**
247: * Processes the data and renders it to a component
248: */
249:
250: public int process(Buffer buffer) {
251:
252: ByteArrayInputStream byteArrayInputStream;
253: MediaContainer mediaContainer;
254:
255: if (buffer.getLength() <= 0)
256: return BUFFER_PROCESSED_OK;
257:
258: if (count < 0) {
259: count++;
260: try {
261: Thread.currentThread().sleep(50);
262: } catch (Exception ex) {
263: ex.printStackTrace();
264: }
265:
266: return BUFFER_PROCESSED_OK;
267: }
268:
269: count = 0;
270:
271: byte[] rawData = (byte[]) (buffer.getData());
272:
273: byteArrayInputStream = new ByteArrayInputStream(rawData);
274: mediaContainer = new MediaContainer(byteArrayInputStream);
275:
276: sound.setSoundData(mediaContainer);
277:
278: if (firstFrame) {
279: firstFrame = false;
280: try {
281: // give J3D more time to initialize
282: Thread.currentThread().sleep(5500);
283: } catch (Exception ex) {
284: ex.printStackTrace();
285: }
286: } else {
287: try {
288: Thread.currentThread().sleep(30);
289: } catch (Exception ex) {
290: ex.printStackTrace();
291: }
292: }
293:
294: // System.out.println("in doProcess");
295: return BUFFER_PROCESSED_OK;
296: }
297:
298: /*************************************************************************
299: * Controller implementation
300: *************************************************************************/
301:
302: public void controllerUpdate(ControllerEvent evt) {
303: if (evt instanceof ConfigureCompleteEvent
304: || evt instanceof RealizeCompleteEvent
305: || evt instanceof PrefetchCompleteEvent) {
306: synchronized (waitSync) {
307: stateTransOK = true;
308: waitSync.notifyAll();
309: }
310: } else if (evt instanceof ResourceUnavailableEvent) {
311: synchronized (waitSync) {
312: stateTransOK = false;
313: waitSync.notifyAll();
314: }
315: } else if (evt instanceof EndOfMediaEvent) {
316: processor.setMediaTime(new Time(0));
317: processor.start();
318: // processor.close();
319: // System.exit(0);
320: }
321: }
322:
323: public boolean waitForState(int state) {
324: synchronized (waitSync) {
325: try {
326: while (processor.getState() != state && stateTransOK) {
327: waitSync.wait();
328: }
329: } catch (Exception ex) {
330: }
331:
332: return stateTransOK;
333: }
334: }
335:
336: }
|