< prev index next >
src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java
Print this page
*** 27,65 ****
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Vector;
! import javax.sound.sampled.*;
// 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
*
* @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
--- 27,65 ----
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Vector;
! 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.
*
* @author Florian Bomers
*/
final class DirectAudioDevice extends AbstractMixer {
private static final int CLIP_BUFFER_TIME = 1000; // in milliseconds
private static final int DEFAULT_LINE_BUFFER_TIME = 500; // in milliseconds
DirectAudioDevice(DirectAudioDeviceProvider.DirectAudioDeviceInfo portMixerInfo) {
// pass in Line.Info, mixer, controls
super(portMixerInfo, // Mixer.Info
null, // Control[]
null, // Line.Info[] sourceLineInfo
*** 166,175 ****
--- 166,176 ----
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,224 ****
}
}
throw new IllegalArgumentException("Line unsupported: " + info);
}
!
public int getMaxLines(Line.Info info) {
Line.Info fullInfo = getLineInfo(info);
// if it's not supported at all, return 0.
if (fullInfo == null) {
--- 215,225 ----
}
}
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,260 ****
}
return 0;
}
!
protected void implOpen() throws LineUnavailableException {
if (Printer.trace) Printer.trace("DirectAudioDevice: implOpen - void method");
}
protected void implClose() {
if (Printer.trace) Printer.trace("DirectAudioDevice: implClose - void method");
}
protected void implStart() {
if (Printer.trace) Printer.trace("DirectAudioDevice: implStart - void method");
}
protected void implStop() {
if (Printer.trace) Printer.trace("DirectAudioDevice: implStop - void method");
}
-
- // IMPLEMENTATION HELPERS
-
int getMixerIndex() {
return ((DirectAudioDeviceProvider.DirectAudioDeviceInfo) getMixerInfo()).getIndex();
}
int getDeviceID() {
--- 232,261 ----
}
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");
}
int getMixerIndex() {
return ((DirectAudioDeviceProvider.DirectAudioDeviceInfo) getMixerInfo()).getIndex();
}
int getDeviceID() {
*** 317,332 ****
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.
--- 318,327 ----
*** 365,375 ****
return hardwareFormats;
}
}
/**
! * 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;
--- 360,370 ----
return hardwareFormats;
}
}
/**
! * 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,405 ****
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,
--- 390,399 ----
*** 412,426 ****
this.waitTime = 10; // 10 milliseconds default wait time
this.isSource = isSource;
}
!
! // ABSTRACT METHOD IMPLEMENTATIONS
!
! // ABSTRACT LINE / DATALINE
!
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);
--- 406,416 ----
this.waitTime = 10; // 10 milliseconds default wait time
this.isSource = isSource;
}
! @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,546 ****
calcVolume();
if (Printer.trace) Printer.trace("<< DirectDL: implOpen() succeeded");
}
!
void implStart() {
if (Printer.trace) Printer.trace(" >> DirectDL: implStart()");
// check for record permission
if (!isSource) {
--- 526,536 ----
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,577 ****
--- 558,568 ----
}
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,607 ****
--- 589,599 ----
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,634 ****
bytePosition = 0;
softwareConversionSize = 0;
if (Printer.trace) Printer.trace("<< DirectDL: implClose() succeeded");
}
! // METHOD OVERRIDES
!
public int available() {
if (id == 0) {
return 0;
}
int a;
--- 615,625 ----
bytePosition = 0;
softwareConversionSize = 0;
if (Printer.trace) Printer.trace("<< DirectDL: implClose() succeeded");
}
! @Override
public int available() {
if (id == 0) {
return 0;
}
int a;
*** 636,646 ****
a = nAvailable(id, isSource);
}
return a;
}
!
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
--- 627,637 ----
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,688 ****
--- 670,680 ----
drained = true;
}
noService = false;
}
+ @Override
public void flush() {
if (id != 0) {
// first stop ongoing read/write method
flushing = true;
synchronized(lock) {
*** 697,706 ****
--- 689,699 ----
drained = true;
}
}
// replacement for getFramePosition (see AbstractDataLine)
+ @Override
public long getLongFramePosition() {
long pos;
synchronized (lockNative) {
pos = nGetBytePosition(id, isSource, bytePosition);
}
*** 711,721 ****
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
*/
--- 704,713 ----
*** 784,793 ****
--- 776,786 ----
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,834 ****
rightGain = gain;
}
}
}
-
/////////////////// CONTROLS /////////////////////////////
protected final class Gain extends FloatControl {
private float linearGain = 1.0f;
--- 817,826 ----
*** 842,851 ****
--- 834,844 ----
-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,875 ****
float getLinearGain() {
return linearGain;
}
} // class Gain
-
private final class Mute extends BooleanControl {
private Mute() {
super(BooleanControl.Type.MUTE, false, "True", "False");
}
public void setValue(boolean newValue) {
super.setValue(newValue);
calcVolume();
}
} // class Mute
--- 852,868 ----
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,888 ****
--- 872,882 ----
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,929 ****
private Pan() {
super(FloatControl.Type.PAN, -1.0f, 1.0f, (1.0f / 128.0f), -1, 0.0f,
"", "Left", "Center", "Right");
}
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 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);
--- 892,919 ----
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 static final class DirectSDL extends DirectDL
implements SourceDataLine {
private DirectSDL(DataLine.Info info,
AudioFormat format,
int bufferSize,
DirectAudioDevice mixer) {
super(info, mixer, format, bufferSize, mixer.getMixerIndex(), mixer.getDeviceID(), true);
*** 931,956 ****
}
}
/**
! * 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
!
public int read(byte[] b, int off, int len) {
flushing = false;
if (len == 0) {
return 0;
}
--- 921,944 ----
}
}
/**
! * Private inner class representing a TargetDataLine.
*/
private static final class DirectTDL extends DirectDL
implements TargetDataLine {
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");
}
! @Override
public int read(byte[] b, int off, int len) {
flushing = false;
if (len == 0) {
return 0;
}
*** 1028,1048 ****
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
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);
--- 1016,1036 ----
private int loopEndFrame; // the last sample included in the loop
// auto closing clip support
private boolean autoclosing = false;
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,1119 ****
getEventDispatcher().autoClosingClipOpened(this);
}
if (Printer.trace) Printer.trace("< DirectClip.open completed");
}
!
public void open(AudioInputStream stream) throws LineUnavailableException, IOException {
// $$fb part of fix for 4679187: Clip.open() throws unexpected Exceptions
Toolkit.isFullySpecifiedAudioFormat(format);
--- 1097,1107 ----
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,1196 ****
if (Printer.trace) Printer.trace("< DirectClip.open(stream) succeeded");
} // synchronized
}
!
public int getFrameLength() {
return m_lengthInFrames;
}
!
public long getMicrosecondLength() {
return Toolkit.frames2micros(getFormat(), getFrameLength());
}
!
public void setFramePosition(int frames) {
if (Printer.trace) Printer.trace("> DirectClip: setFramePosition: " + frames);
if (frames < 0) {
frames = 0;
--- 1164,1184 ----
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,1236 ****
--- 1215,1225 ----
+" 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,1260 ****
//return newFramePosition;
//}
return super.getLongFramePosition();
}
!
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");
}
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);
--- 1230,1250 ----
//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,1311 ****
if (Printer.trace) Printer.trace(" loopStart: " + loopStartFrame + " loopEnd: " + loopEndFrame);
if (Printer.trace) Printer.trace("< DirectClip: setLoopPoints completed");
}
!
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
!
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);
}
void implClose() {
if (Printer.trace) Printer.trace(">> DirectClip: implClose()");
// dispose of thread
Thread oldThread = thread;
--- 1271,1299 ----
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();
}
! @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,1347 ****
getEventDispatcher().autoClosingClipClosed(this);
if (Printer.trace) Printer.trace("<< DirectClip: implClose() succeeded");
}
!
void implStart() {
if (Printer.trace) Printer.trace("> DirectClip: implStart()");
super.implStart();
if (Printer.trace) Printer.trace("< DirectClip: implStart() succeeded");
}
void implStop() {
if (Printer.trace) Printer.trace(">> DirectClip: implStop()");
super.implStop();
// reset loopCount field so that playback will be normal with
--- 1319,1336 ----
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,1360 ****
loopCount = 0;
if (Printer.trace) Printer.trace("<< DirectClip: implStop() succeeded");
}
-
// main playback loop
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,
--- 1338,1349 ----
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,1429 ****
--- 1405,1420 ----
/* $$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,1442 ****
--- 1424,1434 ----
}
autoclosing = value;
}
}
+ @Override
protected boolean requiresServicing() {
// no need for servicing for Clips
return false;
}
*** 1486,1492 ****
// 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);
-
}
--- 1478,1483 ----
< prev index next >