< prev index next >
src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java
Print this page
@@ -27,39 +27,39 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Vector;
-import javax.sound.sampled.*;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.BooleanControl;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.Control;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.FloatControl;
+import javax.sound.sampled.Line;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.SourceDataLine;
+import javax.sound.sampled.TargetDataLine;
// IDEA:
// Use java.util.concurrent.Semaphore,
// java.util.concurrent.locks.ReentrantLock and other new classes/methods
// to improve this class's thread safety.
-
/**
- * A Mixer which provides direct access to audio devices
+ * A Mixer which provides direct access to audio devices.
*
* @author Florian Bomers
*/
final class DirectAudioDevice extends AbstractMixer {
- // CONSTANTS
private static final int CLIP_BUFFER_TIME = 1000; // in milliseconds
private static final int DEFAULT_LINE_BUFFER_TIME = 500; // in milliseconds
- // INSTANCE VARIABLES
-
- /** number of opened lines */
- private int deviceCountOpened = 0;
-
- /** number of started lines */
- private int deviceCountStarted = 0;
-
- // CONSTRUCTOR
DirectAudioDevice(DirectAudioDeviceProvider.DirectAudioDeviceInfo portMixerInfo) {
// pass in Line.Info, mixer, controls
super(portMixerInfo, // Mixer.Info
null, // Control[]
null, // Line.Info[] sourceLineInfo
@@ -166,10 +166,11 @@
return null;
}
// ABSTRACT MIXER: ABSTRACT METHOD IMPLEMENTATIONS
+ @Override
public Line getLine(Line.Info info) throws LineUnavailableException {
Line.Info fullInfo = getLineInfo(info);
if (fullInfo == null) {
throw new IllegalArgumentException("Line unsupported: " + info);
}
@@ -214,11 +215,11 @@
}
}
throw new IllegalArgumentException("Line unsupported: " + info);
}
-
+ @Override
public int getMaxLines(Line.Info info) {
Line.Info fullInfo = getLineInfo(info);
// if it's not supported at all, return 0.
if (fullInfo == null) {
@@ -231,30 +232,30 @@
}
return 0;
}
-
+ @Override
protected void implOpen() throws LineUnavailableException {
if (Printer.trace) Printer.trace("DirectAudioDevice: implOpen - void method");
}
+ @Override
protected void implClose() {
if (Printer.trace) Printer.trace("DirectAudioDevice: implClose - void method");
}
+ @Override
protected void implStart() {
if (Printer.trace) Printer.trace("DirectAudioDevice: implStart - void method");
}
+ @Override
protected void implStop() {
if (Printer.trace) Printer.trace("DirectAudioDevice: implStop - void method");
}
-
- // IMPLEMENTATION HELPERS
-
int getMixerIndex() {
return ((DirectAudioDeviceProvider.DirectAudioDeviceInfo) getMixerInfo()).getIndex();
}
int getDeviceID() {
@@ -317,16 +318,10 @@
format.getFrameSize(), format.getFrameRate(), format.isBigEndian());
}
return null;
}
-
-
-
- // INNER CLASSES
-
-
/**
* Private inner class for the DataLine.Info objects
* adds a little magic for the isFormatSupported so
* that the automagic conversion of endianness and sign
* does not show up in the formats array.
@@ -365,11 +360,11 @@
return hardwareFormats;
}
}
/**
- * Private inner class as base class for direct lines
+ * Private inner class as base class for direct lines.
*/
private static class DirectDL extends AbstractDataLine implements EventDispatcher.LineMonitor {
protected final int mixerIndex;
protected final int deviceID;
protected long id;
@@ -395,11 +390,10 @@
protected volatile boolean noService = false; // do not run the nService method
// Guards all native calls.
protected final Object lockNative = new Object();
- // CONSTRUCTOR
protected DirectDL(DataLine.Info info,
DirectAudioDevice mixer,
AudioFormat format,
int bufferSize,
int mixerIndex,
@@ -412,15 +406,11 @@
this.waitTime = 10; // 10 milliseconds default wait time
this.isSource = isSource;
}
-
- // ABSTRACT METHOD IMPLEMENTATIONS
-
- // ABSTRACT LINE / DATALINE
-
+ @Override
void implOpen(AudioFormat format, int bufferSize) throws LineUnavailableException {
if (Printer.trace) Printer.trace(">> DirectDL: implOpen("+format+", "+bufferSize+" bytes)");
// $$fb part of fix for 4679187: Clip.open() throws unexpected Exceptions
Toolkit.isFullySpecifiedAudioFormat(format);
@@ -536,11 +526,11 @@
calcVolume();
if (Printer.trace) Printer.trace("<< DirectDL: implOpen() succeeded");
}
-
+ @Override
void implStart() {
if (Printer.trace) Printer.trace(" >> DirectDL: implStart()");
// check for record permission
if (!isSource) {
@@ -568,10 +558,11 @@
}
if (Printer.trace) Printer.trace("<< DirectDL: implStart() succeeded");
}
+ @Override
void implStop() {
if (Printer.trace) Printer.trace(">> DirectDL: implStop()");
// check for record permission
if (!isSource) {
@@ -598,10 +589,11 @@
stoppedWritten = false;
if (Printer.trace) Printer.trace(" << DirectDL: implStop() succeeded");
}
+ @Override
void implClose() {
if (Printer.trace) Printer.trace(">> DirectDL: implClose()");
// check for record permission
if (!isSource) {
@@ -623,12 +615,11 @@
bytePosition = 0;
softwareConversionSize = 0;
if (Printer.trace) Printer.trace("<< DirectDL: implClose() succeeded");
}
- // METHOD OVERRIDES
-
+ @Override
public int available() {
if (id == 0) {
return 0;
}
int a;
@@ -636,11 +627,11 @@
a = nAvailable(id, isSource);
}
return a;
}
-
+ @Override
public void drain() {
noService = true;
// additional safeguard against draining forever
// this occurred on Solaris 8 x86, probably due to a bug
// in the audio driver
@@ -679,10 +670,11 @@
drained = true;
}
noService = false;
}
+ @Override
public void flush() {
if (id != 0) {
// first stop ongoing read/write method
flushing = true;
synchronized(lock) {
@@ -697,10 +689,11 @@
drained = true;
}
}
// replacement for getFramePosition (see AbstractDataLine)
+ @Override
public long getLongFramePosition() {
long pos;
synchronized (lockNative) {
pos = nGetBytePosition(id, isSource, bytePosition);
}
@@ -711,11 +704,10 @@
pos = 0;
}
return (pos / getFormat().getFrameSize());
}
-
/*
* write() belongs into SourceDataLine and Clip,
* so define it here and make it accessible by
* declaring the respective interfaces with DirectSDL and DirectClip
*/
@@ -784,10 +776,11 @@
protected boolean requiresServicing() {
return nRequiresServicing(id, isSource);
}
// called from event dispatcher for lines that need servicing
+ @Override
public void checkLine() {
synchronized (lockNative) {
if (monitoring
&& doIO
&& id != 0
@@ -824,11 +817,10 @@
rightGain = gain;
}
}
}
-
/////////////////// CONTROLS /////////////////////////////
protected final class Gain extends FloatControl {
private float linearGain = 1.0f;
@@ -842,10 +834,11 @@
-1,
0.0f,
"dB", "Minimum", "", "Maximum");
}
+ @Override
public void setValue(float newValue) {
// adjust value within range ?? spec says IllegalArgumentException
//newValue = Math.min(newValue, getMaximum());
//newValue = Math.max(newValue, getMinimum());
@@ -859,17 +852,17 @@
float getLinearGain() {
return linearGain;
}
} // class Gain
-
private final class Mute extends BooleanControl {
private Mute() {
super(BooleanControl.Type.MUTE, false, "True", "False");
}
+ @Override
public void setValue(boolean newValue) {
super.setValue(newValue);
calcVolume();
}
} // class Mute
@@ -879,10 +872,11 @@
private Balance() {
super(FloatControl.Type.BALANCE, -1.0f, 1.0f, (1.0f / 128.0f), -1, 0.0f,
"", "Left", "Center", "Right");
}
+ @Override
public void setValue(float newValue) {
setValueImpl(newValue);
panControl.setValueImpl(newValue);
calcVolume();
}
@@ -898,32 +892,28 @@
private Pan() {
super(FloatControl.Type.PAN, -1.0f, 1.0f, (1.0f / 128.0f), -1, 0.0f,
"", "Left", "Center", "Right");
}
+ @Override
public void setValue(float newValue) {
setValueImpl(newValue);
balanceControl.setValueImpl(newValue);
calcVolume();
}
void setValueImpl(float newValue) {
super.setValue(newValue);
}
} // class Pan
-
-
-
} // class DirectDL
-
/**
- * Private inner class representing a SourceDataLine
+ * Private inner class representing a SourceDataLine.
*/
private static final class DirectSDL extends DirectDL
implements SourceDataLine {
- // CONSTRUCTOR
private DirectSDL(DataLine.Info info,
AudioFormat format,
int bufferSize,
DirectAudioDevice mixer) {
super(info, mixer, format, bufferSize, mixer.getMixerIndex(), mixer.getDeviceID(), true);
@@ -931,26 +921,24 @@
}
}
/**
- * Private inner class representing a TargetDataLine
+ * Private inner class representing a TargetDataLine.
*/
private static final class DirectTDL extends DirectDL
implements TargetDataLine {
- // CONSTRUCTOR
private DirectTDL(DataLine.Info info,
AudioFormat format,
int bufferSize,
DirectAudioDevice mixer) {
super(info, mixer, format, bufferSize, mixer.getMixerIndex(), mixer.getDeviceID(), false);
if (Printer.trace) Printer.trace("DirectTDL CONSTRUCTOR: completed");
}
- // METHOD OVERRIDES
-
+ @Override
public int read(byte[] b, int off, int len) {
flushing = false;
if (len == 0) {
return 0;
}
@@ -1028,21 +1016,21 @@
private int loopEndFrame; // the last sample included in the loop
// auto closing clip support
private boolean autoclosing = false;
- // CONSTRUCTOR
private DirectClip(DataLine.Info info,
AudioFormat format,
int bufferSize,
DirectAudioDevice mixer) {
super(info, mixer, format, bufferSize, mixer.getMixerIndex(), mixer.getDeviceID(), true);
if (Printer.trace) Printer.trace("DirectClip CONSTRUCTOR: completed");
}
// CLIP METHODS
+ @Override
public void open(AudioFormat format, byte[] data, int offset, int bufferSize)
throws LineUnavailableException {
// $$fb part of fix for 4679187: Clip.open() throws unexpected Exceptions
Toolkit.isFullySpecifiedAudioFormat(format);
@@ -1109,11 +1097,11 @@
getEventDispatcher().autoClosingClipOpened(this);
}
if (Printer.trace) Printer.trace("< DirectClip.open completed");
}
-
+ @Override
public void open(AudioInputStream stream) throws LineUnavailableException, IOException {
// $$fb part of fix for 4679187: Clip.open() throws unexpected Exceptions
Toolkit.isFullySpecifiedAudioFormat(format);
@@ -1176,21 +1164,21 @@
if (Printer.trace) Printer.trace("< DirectClip.open(stream) succeeded");
} // synchronized
}
-
+ @Override
public int getFrameLength() {
return m_lengthInFrames;
}
-
+ @Override
public long getMicrosecondLength() {
return Toolkit.frames2micros(getFormat(), getFrameLength());
}
-
+ @Override
public void setFramePosition(int frames) {
if (Printer.trace) Printer.trace("> DirectClip: setFramePosition: " + frames);
if (frames < 0) {
frames = 0;
@@ -1227,10 +1215,11 @@
+" getLongFramePosition()="+getLongFramePosition());
if (Printer.trace) Printer.trace("< DirectClip: setFramePosition");
}
// replacement for getFramePosition (see AbstractDataLine)
+ @Override
public long getLongFramePosition() {
/* $$fb
* this would be intuitive, but the definition of getFramePosition
* is the number of frames rendered since opening the device...
* That also means that setFramePosition() means something very
@@ -1241,20 +1230,21 @@
//return newFramePosition;
//}
return super.getLongFramePosition();
}
-
+ @Override
public synchronized void setMicrosecondPosition(long microseconds) {
if (Printer.trace) Printer.trace("> DirectClip: setMicrosecondPosition: " + microseconds);
long frames = Toolkit.micros2frames(getFormat(), microseconds);
setFramePosition((int) frames);
if (Printer.trace) Printer.trace("< DirectClip: setMicrosecondPosition succeeded");
}
+ @Override
public void setLoopPoints(int start, int end) {
if (Printer.trace) Printer.trace("> DirectClip: setLoopPoints: start: " + start + " end: " + end);
if (start < 0 || start >= getFrameLength()) {
throw new IllegalArgumentException("illegal value for start: "+start);
@@ -1281,31 +1271,29 @@
if (Printer.trace) Printer.trace(" loopStart: " + loopStartFrame + " loopEnd: " + loopEndFrame);
if (Printer.trace) Printer.trace("< DirectClip: setLoopPoints completed");
}
-
+ @Override
public void loop(int count) {
// note: when count reaches 0, it means that the entire clip
// will be played, i.e. it will play past the loop end point
loopCount = count;
start();
}
- // ABSTRACT METHOD IMPLEMENTATIONS
-
- // ABSTRACT LINE
-
+ @Override
void implOpen(AudioFormat format, int bufferSize) throws LineUnavailableException {
// only if audioData wasn't set in a calling open(format, byte[], frameSize)
// this call is allowed.
if (audioData == null) {
throw new IllegalArgumentException("illegal call to open() in interface Clip");
}
super.implOpen(format, bufferSize);
}
+ @Override
void implClose() {
if (Printer.trace) Printer.trace(">> DirectClip: implClose()");
// dispose of thread
Thread oldThread = thread;
@@ -1331,17 +1319,18 @@
getEventDispatcher().autoClosingClipClosed(this);
if (Printer.trace) Printer.trace("<< DirectClip: implClose() succeeded");
}
-
+ @Override
void implStart() {
if (Printer.trace) Printer.trace("> DirectClip: implStart()");
super.implStart();
if (Printer.trace) Printer.trace("< DirectClip: implStart() succeeded");
}
+ @Override
void implStop() {
if (Printer.trace) Printer.trace(">> DirectClip: implStop()");
super.implStop();
// reset loopCount field so that playback will be normal with
@@ -1349,12 +1338,12 @@
loopCount = 0;
if (Printer.trace) Printer.trace("<< DirectClip: implStop() succeeded");
}
-
// main playback loop
+ @Override
public void run() {
if (Printer.trace) Printer.trace(">>> DirectClip: run() threadID="+Thread.currentThread().getId());
while (thread != null) {
// doIO is volatile, but we could check it, then get
// pre-empted while another thread changes doIO and notifies,
@@ -1416,14 +1405,16 @@
/* $$mp 2003-10-01
The following two methods are common between this class and
MixerClip. They should be moved to a base class, together
with the instance variable 'autoclosing'. */
+ @Override
public boolean isAutoClosing() {
return autoclosing;
}
+ @Override
public void setAutoClosing(boolean value) {
if (value != autoclosing) {
if (isOpen()) {
if (value) {
getEventDispatcher().autoClosingClipOpened(this);
@@ -1433,10 +1424,11 @@
}
autoclosing = value;
}
}
+ @Override
protected boolean requiresServicing() {
// no need for servicing for Clips
return false;
}
@@ -1486,7 +1478,6 @@
// returns if the native implementation needs regular calls to nService()
private static native boolean nRequiresServicing(long id, boolean isSource);
// called in irregular intervals
private static native void nService(long id, boolean isSource);
-
}
< prev index next >