001: /*
002: * Copyright (c) 2000 Silvere Martin-Michiellot All Rights Reserved.
003: *
004: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
005: * royalty free, license to use, modify and redistribute this
006: * software in source and binary code form,
007: * provided that i) this copyright notice and license appear on all copies of
008: * the software; and ii) Licensee does not utilize the software in a manner
009: * which is disparaging to Silvere Martin-Michiellot.
010: *
011: * This software is provided "AS IS," without a warranty of any kind. ALL
012: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
013: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
014: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. Silvere Martin-Michiellot
015: * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
016: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
017: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
018: * Silvere Martin-Michiellot OR ITS LICENSORS BE LIABLE
019: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
020: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
021: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
022: * OR INABILITY TO USE SOFTWARE, EVEN IF Silvere Martin-Michiellot HAS BEEN
023: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
024: *
025: * This software is not designed or intended for use in on-line control of
026: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
027: * the design, construction, operation or maintenance of any nuclear
028: * facility. Licensee represents and warrants that it will not use or
029: * redistribute the Software for such purposes.
030: *
031: */
032:
033: package com.db.media.audio;
034:
035: // This code is repackaged after the code AudioLoop.java from Florian Bomers & Matthias Pfisterer from JavaSound Examples
036: // Site http://www.jsresources.org/examples/
037: // Email tritonus-user@lists.sourceforge.net
038:
039: import java.io.*;
040: import javax.sound.sampled.*;
041:
042: /**
043: *
044: * <title>Recording and playing back the recorded data immediately</title>
045: *
046: * <formalpara><title>Purpose</title>
047: * <para>
048: * This program opens two lines: one for recording and one
049: * for playback. In an infinite loop, it reads data from
050: * the recording line and writes them to the playback line.
051: * You can use this to measure the delays inside Java Sound:
052: * Speak into the microphone and wait untill you hear
053: * yourself in the speakers. This can be used to
054: * experience the effect of changing the buffer sizes: use
055: * the <option>-e</option> and <option>-i</option> options.
056: * You will notice that the delays change, too.
057: * </para></formalpara>
058: *
059: * <formalpara><title>Level</title>
060: * <para>advanced</para></formalpara>
061: *
062: * <formalpara><title>Usage</title>
063: * <para>
064: * <cmdsynopsis>
065: * <command>java AudioDelay</command>
066: * <arg choice="plain"><option>-l</option></arg>
067: * </cmdsynopsis>
068: * <cmdsynopsis>
069: * <command>java AudioDelay</command>
070: * <arg><option>-M <replaceable>mixername</replaceable></option></arg>
071: * <arg><option>-e <replaceable>buffersize</replaceable></option></arg>
072: * <arg><option>-i <replaceable>buffersize</replaceable></option></arg>
073: * </cmdsynopsis>
074: * </para></formalpara>
075: *
076: * <formalpara><title>Parameters</title>
077: * <variablelist>
078: * <varlistentry>
079: * <term><option>-l</option></term>
080: * <listitem><para>lists the available mixers</para></listitem>
081: * </varlistentry>
082: * <varlistentry>
083: * <term><option>-M <replaceable>mixername</replaceable></option></term>
084: * <listitem><para>selects a mixer to play on</para></listitem>
085: * </varlistentry>
086: * <varlistentry>
087: * <term><option>-e <replaceable>buffersize</replaceable></option></term>
088: * <listitem><para>the buffer size to use in the application ("extern")</para></listitem>
089: * </varlistentry>
090: * <varlistentry>
091: * <term><option>-i <replaceable>buffersize</replaceable></option></term>
092: * <listitem><para>the buffer size to use in Java Sound ("intern")</para></listitem>
093: * </varlistentry>
094: * </variablelist>
095: * </formalpara>
096: *
097: * <formalpara><title>Bugs, limitations</title>
098: * <para>
099: * There is no way to stop the program besides brute force
100: * (ctrl-C). There is no way to set the audio quality.
101: * </para>
102: *
103: * <para>The example requires that the soundcard and its driver
104: * as well as the Java Sound implementation support full-duplex
105: * operation. In Linux either use <ulink
106: * url="http://www.tritonus.org/">Tritonus</ulink> or enable
107: * full-duplex in Sun's Java Sound implementation (search the
108: * archive of java-linux).</para>
109: * </formalpara>
110: *
111: */
112: public class AudioDelay extends Thread {
113:
114: private static final int DEFAULT_INTERNAL_BUFSIZ = 40960;
115: private static final int DEFAULT_EXTERNAL_BUFSIZ = 40960;
116:
117: private TargetDataLine targetLine;
118: private SourceDataLine sourceLine;
119: private boolean recording;
120: private int nExternalBufferSize;
121:
122: /*
123: * We have to pass an AudioFormat to describe in which
124: * format the audio data should be recorded and played.
125: */
126: public AudioDelay(AudioFormat format, int nInternalBufferSize,
127: int nExternalBufferSize, String strMixerName)
128: throws LineUnavailableException {
129:
130: Mixer mixer = null;
131: if (strMixerName != null) {
132: Mixer.Info mixerInfo = getMixerInfo(strMixerName);
133: mixer = AudioSystem.getMixer(mixerInfo);
134: }
135: DataLine.Info targetInfo = new DataLine.Info(
136: TargetDataLine.class, format, nInternalBufferSize);
137: DataLine.Info sourceInfo = new DataLine.Info(
138: SourceDataLine.class, format, nInternalBufferSize);
139: if (mixer != null) {
140: targetLine = (TargetDataLine) mixer.getLine(targetInfo);
141: sourceLine = (SourceDataLine) mixer.getLine(sourceInfo);
142: } else {
143: targetLine = (TargetDataLine) AudioSystem
144: .getLine(targetInfo);
145: sourceLine = (SourceDataLine) AudioSystem
146: .getLine(sourceInfo);
147: }
148: targetLine.open(format, nInternalBufferSize);
149: sourceLine.open(format, nInternalBufferSize);
150: this .nExternalBufferSize = nExternalBufferSize;
151:
152: }
153:
154: public void start() {
155:
156: targetLine.start();
157: sourceLine.start();
158: super .start();
159:
160: }
161:
162: public void stopRecording() {
163:
164: targetLine.stop();
165: sourceLine.stop();
166: targetLine.close();
167: sourceLine.close();
168: recording = false;
169:
170: }
171:
172: public void run() {
173:
174: byte[] abBuffer = new byte[nExternalBufferSize];
175: int nBufferSize = abBuffer.length;
176: recording = true;
177: while (recording) {
178: int nBytesRead = targetLine.read(abBuffer, 0, nBufferSize);
179: sourceLine.write(abBuffer, 0, nBytesRead);
180: }
181:
182: }
183:
184: public static void main(String[] args) {
185:
186: String strMixerName = null;
187: float fFrameRate = 44100.0F;
188: int nInternalBufferSize = DEFAULT_INTERNAL_BUFSIZ;
189: int nExternalBufferSize = DEFAULT_EXTERNAL_BUFSIZ;
190:
191: AudioFormat audioFormat = new AudioFormat(
192: AudioFormat.Encoding.PCM_SIGNED, fFrameRate, 16, 2, 4,
193: fFrameRate, false);
194: AudioDelay audioDelay = null;
195: try {
196: audioDelay = new AudioDelay(audioFormat,
197: nInternalBufferSize, nExternalBufferSize,
198: strMixerName);
199: } catch (LineUnavailableException e) {
200: e.printStackTrace();
201: System.exit(1);
202: }
203:
204: audioDelay.start();
205:
206: }
207:
208: private static Mixer.Info getMixerInfo(String strMixerName) {
209:
210: Mixer.Info[] aInfos = AudioSystem.getMixerInfo();
211: for (int i = 0; i < aInfos.length; i++) {
212: if (aInfos[i].getName().equals(strMixerName)) {
213: return aInfos[i];
214: }
215: }
216:
217: return null;
218:
219: }
220:
221: }
|