1. DataLines |
- 1.1. General
- 1.1.1. How can I be notified when data is available for
write/read in a SourceDataLine or
TargetDataLine?
- 1.1.2. Why does it fail to open any line with 16 kHz sample
rate?
- 1.1.3. How can I get a
SourceDataLine or
TargetDataLine in μ-law
format?
- 1.1.4. Why does simultaneous recording and playback only
work when first opening the playback line
(SourceDataLine)?
- 1.1.5. Why doesn't simultaneous recording and playback work
at all with the Sun JDK 1.3/1.4 on GNU/Linux?
- 1.1.6. How can I get a
Line from a specific
Mixer?
- 1.1.7. Why are there no mono lines
with the "Direct Audio Devices" mixers on Linux?
- 1.1.8. Why is a SourceDataLine
called "source" and a
TargetDataLine called "target"
though it's actually the other way round?
- 1.1.9. Why are
DataLine.getFramePosition() and
DataLine.getMicrosecondPosition() so
inaccurate?
- 1.1.10. Why does DataLine.getLevel()
always return -1?
- 1.1.11. What is the difference
between DataLine.isActive() and
DataLine.isRunning()?
- 1.1.12. How can I detect a buffer
underrun or overrun?
- 1.1.13. Why is there no event for
notifying applications of an underrun/overrun
condition?
- 1.1.14. How can I find out the current
playback or recording position?
- 1.1.15. How can I do looping in
playback?
- 1.2. SourceDataLine
- 1.2.1. How can I avoid that the last bit
of sound played on a SourceDataLine
is repeated?
- 1.2.2. Why is playback distorted, too
fast or too slow with the JDK 1.5.0 beta, but not with
earlier versions of the JDK?
- 1.3. TargetDataLine
- 1.3.1. How can I capture from a
specific source (microphone or line-in)?
- 1.3.2. How can I get more than one
TargetDataLine?
- 1.3.3. Why is in not possible to open more than one
TargetDataLine at the same
time?
- 1.3.4. Why do I get a LineUnavailableException: "Requested
format incompatible with already established device
format"?
- 1.3.5. How can I control the volume when recording with a
TargetDataLine?
- 1.3.6. How should I use
stop() and
drain() on a
TargetDataLine?
- 1.3.7. Why is
TargetDataLine.read() blocking for a
long time?
- 1.3.8. Why is the end of
recordings cut off prematurely?
- 1.4. Clip
- 1.4.1. Why do I get an out of memory
exception when trying to use a Clip
with a 5 MB audio file?
- 1.4.2. Why do I get "LineUnavailableException: No Free
Voices" when opening a Clip?
- 1.4.3. How can I rewind a Clip?
- 1.4.4. Why does the
frame/microsecond position not jump back to zero when a
Clip is looped?
- 1.4.5. Why are there failures,
clicks and other random effects if a clip is played
multiple times with 1.5?
| |
1.1. General |
- 1.1.1. How can I be notified when data is available for
write/read in a SourceDataLine or
TargetDataLine?
- 1.1.2. Why does it fail to open any line with 16 kHz sample
rate?
- 1.1.3. How can I get a
SourceDataLine or
TargetDataLine in μ-law
format?
- 1.1.4. Why does simultaneous recording and playback only
work when first opening the playback line
(SourceDataLine)?
- 1.1.5. Why doesn't simultaneous recording and playback work
at all with the Sun JDK 1.3/1.4 on GNU/Linux?
- 1.1.6. How can I get a
Line from a specific
Mixer?
- 1.1.7. Why are there no mono lines
with the "Direct Audio Devices" mixers on Linux?
- 1.1.8. Why is a SourceDataLine
called "source" and a
TargetDataLine called "target"
though it's actually the other way round?
- 1.1.9. Why are
DataLine.getFramePosition() and
DataLine.getMicrosecondPosition() so
inaccurate?
- 1.1.10. Why does DataLine.getLevel()
always return -1?
- 1.1.11. What is the difference
between DataLine.isActive() and
DataLine.isRunning()?
- 1.1.12. How can I detect a buffer
underrun or overrun?
- 1.1.13. Why is there no event for
notifying applications of an underrun/overrun
condition?
- 1.1.14. How can I find out the current
playback or recording position?
- 1.1.15. How can I do looping in
playback?
| |
| 1.1.1. | How can I be notified when data is available for
write/read in a SourceDataLine or
TargetDataLine? |
| You have to use
SourceDataLine/TargetDataLine.available(). The
usual implementation for streaming audio (in Java Sound)
is a dedicated thread for that - look at the Java Sound
Demo which you can download from Sun or at the Java Sound Resources: Examples. (Florian) |
| 1.1.2. | Why does it fail to open any line with 16 kHz sample
rate? |
| Apparently, most Java Sound implementations do not
provide that, even if the soundcard supports it. Future
implementations will support that. (Florian) |
| 1.1.3. | How can I get a
SourceDataLine or
TargetDataLine in μ-law
format? |
| TargetDataLines are supposed
to act as a "direct" way to communicate with the
audio hardware device, i.e. your soundcard. When your
soundcard does not support μ-law directly, the
TargetDataLine won't either. The way to go is to open a
TargetDataLine in pcm format and
route it through a format converter. See doc of
AudioSystem to get converted
Streams. The converted stream you get provides μ-law
samples then. There is no drawback in this approach: all PC
soundcards that I know of deliver only PCM, so it has to
be rendered to μ-law anyway in software. Whether in the
soundcard's driver, the operating system layer or in the
application (your java program) doesn't matter. You get
maximum portability when only using pcm for
TargetDataLines. (Florian) |
| 1.1.4. | Why does simultaneous recording and playback only
work when first opening the playback line
(SourceDataLine)? |
| This depends on the soundcard and its driver to the
native operating system. E.g. Soundblaster 16 or 64 do not
provide real full duplex, only a kind of pseudo full
duplex. I experienced under Windows that you can only use
this pseudo full duplex when you have a certain order in
opening record/playback lines. (Florian) |
| 1.1.5. | Why doesn't simultaneous recording and playback work
at all with the Sun JDK 1.3/1.4 on GNU/Linux? |
| Due to problems with some OSS drivers, full-duplex
is disabled by default in versions up to 1.4.1. There are
several ways to get full-duplex: Use the ALSA support
in JDK 1.4.2 or later. Note that in 1.4.2, the ALSA
support is not used by default for playback. If you call
AudioSytem.getLine(), the default
is used ("Java Sound Audio Engine"). To use the "Direct
Audio Device" (which uses ALSA), obtain the respective
mixer with AudioSystem.getMixer()
and call getLine() on the mixer. To
detect the "Direct Audio Device", look for a string
"ALSA" in the vendor or description string of the
Mixer.Info object. Although string comparison is not a
nice way, it is higly likely that "ALSA" will appear in
at least one of the string in future releases. For
recording, the "Direct Audio Device" is the default. A
way to make the is the default for playback, too, is to
rename /dev/audio and
/dev/dsp. However, this will
disable sound support for all non-ALSA programs. In
version 1.5, the "Direct Audio Device" are the default
for playback, too, if the soundcard supports mixing in
hardware. Use Tritonus. The
Tritonus plug-ins work with Java versions that are older
than 1.4.2, too. However, it is recommended to use 1.4.2
if possible. The ALSA support in 1.4.2 is more stable
than the one in Tritonus.
See also Q: 3.3 (Matthias) |
| 1.1.6. | How can I get a
Line from a specific
Mixer? |
| Obtain the list of available
Mixer implementations with AudioSystem.getMixerInfo(). Select
one of the available and call AudioSystem.getMixer(Mixer.Info)
to obtain the Mixer. With this
object you can call Mixer.getLine(Line.Info)
instead of AudioSystem.getLine(Line.Info). In
the JDK 1.5.0, you can also use the ease-of-use methods in
AudioSystem: With the JDK 1.5.0, there is an additional
possibility: The default provider properties can be used
to select the default Mixer for
each type of line (SourceDataLine,
TargetDataLine,
Clip,
Port). The default
Mixer, if available, is used in
AudioSystem.getLine(). For details,
see the specification.
(Matthias) |
| 1.1.7. | Why are there no mono lines
with the "Direct Audio Devices" mixers on Linux? |
| The implementation of the "Direct Audio Device"
queries the soundcard driver for the supported
formats. Some ALSA drivers do not support mono lines, so
they are not available in the "Direct Audio Device". The
workaround is to open a stereo line and expand the mono
data to stereo. See also How can I convert between mono
and stereo? and How can I make a mono stream
appear on one channel of a stereo stream?
(Matthias) |
| 1.1.8. | Why is a SourceDataLine
called "source" and a
TargetDataLine called "target"
though it's actually the other way round? |
| Well, nobody really knows why this fancy naming was
chosen. From the perspective of an application, it's
counter-intuitive. To understand it, take the perspective
of a Mixer object: It receives data
from the application via a
SourceDataLine object, this is its
source of data. And it delivers data to the application
via a TargetDataLine. So from the
perspective of the Mixer, this is
the target of its data. (Matthias) |
| 1.1.9. | Why are
DataLine.getFramePosition() and
DataLine.getMicrosecondPosition() so
inaccurate? |
| The implementation of these methods in the "Java
Sound Audio Engine" is bad and will not be fixed. The
"Direct Audio Device" has a much better
implementation. See also What are all these mixers? But keep in mind that it is not possible to get a
frame precise playback position with these methods. There
is too much buffering in the data path (also in the audio
hardware), so calculating the position is always only an
estimation. If you try to measure the precision of
DataLine.getMicrosecondPosition()
with a real-time clock, you are also likely to see the
effect of a clock drift. For details on this phenomenon
see Why does recording or playing for a
certain period of time results in audio data that is shorter
or longer than the period I recorded / played?
(Matthias) |
| 1.1.10. | Why does DataLine.getLevel()
always return -1? |
| DataLine.getLevel() is not
implemented in current versions of the Sun JDK (1.4.1),
nor in any other known Java Sound implementation. Here is
a suggestion from Florian Bomers on how to implement this
functionality yourself: Read the data from the TargetDataLine in
blocks. Convert each block to a common format,
e.g. normalized floats [-1, +1], or 8 bit signed
bytes. If your project can make use of LGPL'd code, have
a look at class FloatSampleBuffer
(for floats) or TConversionTool
(for integer-based values) of the Tritonus
project. Calculate the level of the block. This
could be the average, RMS power, peak amplitude, or
similar. Be sure to use the absolute values (or squaring
the amplitudes for the power). See also How can I calculate the power
of a signal?
(Matthias) |
| 1.1.11. | What is the difference
between DataLine.isActive() and
DataLine.isRunning()? |
| This is an issue where even the Java Sound gurus do
not know a satisfying answer. A useful definition would be
the following: isActive() returns true if
the line is in started state, i.e. between calls to
start() and
stop(). isRunning() returns true if
data is actually read from or written to the
device. This would mean that
isRunning() returns false in case
of buffer underruns or overruns.
However, this is not the way it is implemented. For
the "Direct Audio Device" mixers,
isActive() and
isRunning() always return the same
value. In general, it is recommended to use
isActive(), since it is specified
less ambigously and it is implemented consistently. See
also bug
#4791152. (Matthias) |
| 1.1.12. | How can I detect a buffer
underrun or overrun? |
| The following is working reliably at least with the
"Direct Audio Device" mixers: SourceDataLine: underrun
if (line.available() == line.getBufferSize()) SourceDataLine.available():
how much data can be written to the buffer. If the
whole buffer can be written to, there is no data in
the buffer to be rendered. TargetDataLine: overrun
if (line.available() == line.getBufferSize()) TargetDataLine.available():
how much data can be read from the buffer. If the
whole buffer can be read, there is no space in the
buffer for new data captured from the line.
(Matthias) |
| 1.1.13. | Why is there no event for
notifying applications of an underrun/overrun
condition? |
| This is Florian's (and my) opinion: Java Sound is a low level audio API. We decided to
give highest priority to performance and "bare"
functionality, rather than adding many high-level
features. And although this is not a reason to not add
it, all low level audio API's that I have worked closely
with do not provide underrun notification.
(Matthias) |
| 1.1.14. | How can I find out the current
playback or recording position? |
| There are two possibilities: Use DataLine.getFramePosition()
or DataLine.getFramePosition(). These
methods are supposed to return the current "hearing"
position. However, they weren't implemented well prior
to the JDK 1.5.0. Count the frames that you read from or write to
the DataLine and add one full
buffer size and 15 milliseconds (ballpark figure for
hardware delay) to it. As reference point use the time
when the write()/read() method returns. This allows
amount correct extrapolation. This method works best
if you call
read()/write()
with buffers that fit exactly into the line's buffer
size. This approach also works reasonably fine with
1.4.2 and before. It is implemented in the JAM program
at J1 2003.
(Matthias) |
| 1.1.15. | How can I do looping in
playback? |
| There are two possibilities: (Matthias) |
1.2. SourceDataLine |
- 1.2.1. How can I avoid that the last bit
of sound played on a SourceDataLine
is repeated?
- 1.2.2. Why is playback distorted, too
fast or too slow with the JDK 1.5.0 beta, but not with
earlier versions of the JDK?
| |
| 1.2.1. | How can I avoid that the last bit
of sound played on a SourceDataLine
is repeated? |
| This can be avoided easily: after writing all data
to the SourceDataLine call
drain() and
stop(). If you want to reuse the line
after this, call start() again before
writing more data to the line. (Matthias) |
| 1.2.2. | Why is playback distorted, too
fast or too slow with the JDK 1.5.0 beta, but not with
earlier versions of the JDK? |
| The reason is a common misconception about how
Line.open()
works. According to the specification,
open() without parameters opens a
line in a "default format". The default format of a line
is an implementation specific property. It is
not the
AudioFormat used in the
DataLine.Info object. Rather, the
format in DataLine.Info is used to
request a DataLine instance that is
capable of handling this format. This
does not necessarily mean that the line has to be opened
in that format. Note that it is possible to construct
DataLine.Info with an array of
AudioFormat objects. This means
that the requested line has to be able to handle any of
the given formats. The Java Sound implementaion prior to JDK 1.5.0 had
the following property: If only one
AudioFormat is given in a
DataLine.Info, this
AudioFormat becomes the default
format of the line. This caused the behaviour that it was
possible to specify the format for
open() via the
DataLine.Info object. However, this
behaviour was never specified, it is just an
implementation specific property you can't rely on in
general. The "Direct Audio Device" mixers in JDK 1.5.0
beta (see also What are all these mixers?) behave different: they just pick one
of the supported hardware formats as default format. This
is a correct behaviour according to the specification,
since the specification doesn't specify how the default
format is chosen. Therefore, it is recommended to always specify the
format when opening a DataLine: use
open(AudioFormat format) or
open(AudioFormat format, int
buffersize) rather than
Line.open() without parameters. See
also Line.open(),
SourceDataLine.open(AudioFormat),
SourceDataLine.open(AudioFormat,
int), TargetDataLine.open(AudioFormat)
and TargetDataLine.open(AudioFormat,
int) It was decided to change the behaviour for the final
version of the JDK 1.5.0 to provide backward compatibility
with the JDK 1.4. The former unportable technique will be
specified behaviour. See also bugs #5053380
and #5067526
(Matthias) |
1.3. TargetDataLine |
- 1.3.1. How can I capture from a
specific source (microphone or line-in)?
- 1.3.2. How can I get more than one
TargetDataLine?
- 1.3.3. Why is in not possible to open more than one
TargetDataLine at the same
time?
- 1.3.4. Why do I get a LineUnavailableException: "Requested
format incompatible with already established device
format"?
- 1.3.5. How can I control the volume when recording with a
TargetDataLine?
- 1.3.6. How should I use
stop() and
drain() on a
TargetDataLine?
- 1.3.7. Why is
TargetDataLine.read() blocking for a
long time?
- 1.3.8. Why is the end of
recordings cut off prematurely?
| |
| 1.3.1. | How can I capture from a
specific source (microphone or line-in)? |
| You can use the system mixer of your operating
system to select the recording source in the same way you
would do it for a native program. With newer versions of
the Sun JDK, you can achieve the same by using the interface
javax.sound.sampled.Port. See
the section Ports for details. (Matthias) |
| 1.3.2. | How can I get more than one
TargetDataLine? |
| Current implementations of the Java Sound API do not
support multiple TargetDataLines
for the same recording source. There are no plans to
change this behaviour. If, in the future, multi-channel
soundcards are supported, it may be possible to get
different TargetDataLine instances
for the different inputs. If you just want to "split"
lines, do it in your application. See also Can I use multi-channel
sound?
(Matthias) |
| 1.3.3. | Why is in not possible to open more than one
TargetDataLine at the same
time? |
| Well, because it's a bug. The above is true for the
Sun JDK up to version 1.4.2 on Solaris and Windows, and up
to 1.4.1 on Linux. Beginning with version 1.5.0 for
Solaris and Windows and version 1.4.2 for Linux there are
the new "Direct Audio Device" mixer that don't have this
limitation. Tritonus is unaffected by this
limitation. (Matthias) |
| 1.3.4. | Why do I get a LineUnavailableException: "Requested
format incompatible with already established device
format"? |
| This is a bug that was fixed for 1.4.2. If you have
to use an older version, there are two possible
workarounds: Do not play back anything using the "Java Sound
Audio Engine" before recording. In version prior to
1.4.2, there is no way of doing playback at all
without using the "Java Sound Audio Engine". If the
"Java Sound Audio Engine" is used, it results in
opening the sound device for 44100 Hz, 16 bit stereo,
thereby setting the "previously established
format". Always capture at 16 bit, stereo, 44100Hz. If
you need your sound data in a different format, you
can convert it afterwards. See also Conversion between sample
representations
and How can I do sample rate
conversion?
(Matthias) |
| 1.3.5. | How can I control the volume when recording with a
TargetDataLine? |
| The obvious solution would be to get a
Control object of type
VOLUME or
MASTER_GAIN for the
TargetDataLine and manipulate the
volume via this object. However, this is not possible,
since no known Java Sound implementation supports any
controls for TargetDataLine
instances. What you can do is to use the system mixer to
control the recording volume --- it affects hardware
settings in the soundcard. One possibility is to use the
mixer application of the operating system. The other
possibility is using Port lines
from inside a Java Sound application. See the section
Ports for
details. The remaining possibility is to implement a volume
control digitally: multiplying each single sample of the
sound data with a certain value that lowers or raises the
level proportionally. See also Change the amplitude (volume) of an audio file (Matthias) |
| 1.3.6. | How should I use
stop() and
drain() on a
TargetDataLine? |
| It is specified that
TargetDataLine.drain() has to wait
until all data has been delivered to the
TargetDataLine. If the line is not
yet stopped, there is always data being delivered to the
line. So you should call drain() only after stop(). In
fact, drain() isn't needed with
TargetDataLine at all. A common technique to terminate reading from a
TargetDataLine is the
following:
TDL.stop();
do
{
count = TDL.read();
}
while (count > 0);
TDL.close();For an implementation of
TargetDataLine.drain() to be 100%
compliant you need to block when the line is started and
there is still data available. One way to do this is the
following:
public void drain()
{
while (isActive() && (available() > 0))
{
Thread.sleep(100);
}
}(Matthias) |
| 1.3.7. | Why is
TargetDataLine.read() blocking for a
long time? |
| By specification,
TargetDataLine.read() is a blocking
call: it waits until the requested amount of data is
available. To use read() in a
non-blocking manner, you can check how much data is
available with available() and
request only that amount. If you want to use
read() in a standard blocking manner,
but need quick response for a real-time application, use
smaller buffers for reading. See also What is the minimum buffer size
I can use?
(Matthias) |
| 1.3.8. | Why is the end of
recordings cut off prematurely? |
| Even after calling stop() on
a TargetDataLine, there may be
data remaining in its internal buffer. Make sure you read
data until there is no more available. Then you can call
close() on the line. See also How should I use
stop() and
drain() on a
TargetDataLine?
(Matthias) |
1.4. Clip |
- 1.4.1. Why do I get an out of memory
exception when trying to use a Clip
with a 5 MB audio file?
- 1.4.2. Why do I get "LineUnavailableException: No Free
Voices" when opening a Clip?
- 1.4.3. How can I rewind a Clip?
- 1.4.4. Why does the
frame/microsecond position not jump back to zero when a
Clip is looped?
- 1.4.5. Why are there failures,
clicks and other random effects if a clip is played
multiple times with 1.5?
| |
| 1.4.1. | Why do I get an out of memory
exception when trying to use a Clip
with a 5 MB audio file? |
| For files of this size, you should stream the
audio. Like that you treat buffers of small size and feed
them successively into the audio device. Look at the
Java Sound Resources: Examples, there are some streaming
audio players to take as a start. (Florian) |
| 1.4.2. | Why do I get "LineUnavailableException: No Free
Voices" when opening a Clip? |
| This happens with the "Java Sound Audio Engine" when
too many clips are open. While you can obtain any number
of Clip instances, only 32 can be
open at the same time. This is a hard limitation of the
engine; it can only mix 32 channels. As a workaround, you
can close unused clips and open them once they are needed
again. If you really need more than 32 channels, you can
do the mixing in your application and output the result to
a SourceDataLine. (Matthias) |
| 1.4.3. | How can I rewind a Clip? |
| Stop the clip by calling
stop(), then use
clip.setFramePosition(0) or
clip.setMicrosecondPosition(0). Alternativly,
you can set looping points so that rewinding occurs
automatically: clip.setLoopPoints(0,
-1) (In this case you have to call
clip.loop(...) instead of
clip.start().) (Matthias) |
| 1.4.4. | Why does the
frame/microsecond position not jump back to zero when a
Clip is looped? |
| getFramePosition() and
getMicrosecondPosition() are
specified to return the position corresponding to the time
since the line (or clip) was opened. If you want to get
the position inside the loop of a looping clip, you can
use something similar to this (assuming you are looping
over the whole length of the clip):
currentFrame = clip.getFramePosition() %
clip.getFrameLength(); (Matthias) |
| 1.4.5. | Why are there failures,
clicks and other random effects if a clip is played
multiple times with 1.5? |
| This is a bug, and apparently one not easy to
fix. See bug #6251460.
Note that you can work around this issue by using the old
"Java Sound Audio Engine" instead of the "Direct Audio
Device" mixers. This way, you get the same behaviour as in
1.4. See also What are all these mixers?
(Matthias) |
2. Controls |
- 2.1. Why does the SourceDataLine
instances I get when using the "Direct Audio Device" (ALSA on
Linux) have no controls?
- 2.2. What is the difference between a
BALANCE and a PAN
control? Which one should I use?
- 2.3. Why do mono lines from a "Direct Audio Device" have no
PAN control?
- 2.4. Why does obtaining a gain
control work with 1.4.2, but not with 1.5.0?
- 2.5. Why do
Clip and
SourceDataLine instances have no
VOLUME control?
- 2.6. Why is there no sample rate control in 1.5.0?
| |
| 2.1. | Why does the SourceDataLine
instances I get when using the "Direct Audio Device" (ALSA on
Linux) have no controls? |
| Lines from these mixers do not provide controls in
1.4.2. In Florian's original opinion, "any control would
obscure the initial idea, to provide high-performance direct
audio access". However, he changed his mind and implemented
volume and balance controls in 1.5.0. (Matthias) |
| 2.2. | What is the difference between a
BALANCE and a PAN
control? Which one should I use? |
| In music, pan knobs are used for mono input lines to
control how they are mapped to stereo output lines. On the
other hand, for stereo input lines, the knob is labelled
"balance". So you should get a PAN
control for mono lines and a BALANCE
control for stereo lines (and none for lines with more than
2 channels). In the Sun J2SDK, PAN controls
behave like BALANCE controls for stereo
lines and BALANCE like
PAN for mono lines. However, this is
only a convenience for compatibility. To write portable
programs, you should not rely on this behaviour.
(Matthias) |
| 2.3. | Why do mono lines from a "Direct Audio Device" have no
PAN control? |
| To implement a PAN control for a
mono line, it has to be "distributed" between the left and
right channel of a stereo line. This was no problem with the
"Java Sound Audio Engine". The "Java Sound Audio Engine"
always opens the soundcard in stereo, so it is always
possible to do this "distribution". The "Direct Audio
Device" implementation, however, opens the soundcard in mono
if a mono line is requested. So it's not possible to
implement a PAN control for such
lines. The workaround is to work with stereo: convert your
stream to stereo and open the
SourceDataLine in that stereo format.
Then this line will have a BALANCE control, which works like
a PAN control. See also How can I convert between mono
and stereo? and What is the difference between a
BALANCE and a PAN
control? Which one should I use?
(Matthias) |
| 2.4. | Why does obtaining a gain
control work with 1.4.2, but not with 1.5.0? |
| Gain
(FloatControl.Type.MASTER_GAIN /
FloatControl.Type.VOLUME) controls are
still available with the "Direct Audio Device" mixers in
1.5.0 (see also What are all these mixers?). However, the behaviour has been
changed so that controls are only available after the line
has been opened. This was necessary because in general, some
control are only available if the device driver supports
certain features, which can be queried only after the
respective device has been opened. (Matthias) |
| 2.5. | Why do
Clip and
SourceDataLine instances have no
VOLUME control? |
| Clip and
SourceDataLine instances provide a
FloatControl.Type.MASTER_GAIN control
rather than a FloatControl.Type.VOLUME
control to control the playback volume. See also Why does obtaining a gain
control work with 1.4.2, but not with 1.5.0? (Matthias) |
| 2.6. | Why is there no sample rate control in 1.5.0? |
| The "Direct Audio Device" mixers in 1.5 (see What are all these mixers?) do not provide a
sample rate control. To cite Florian: “This is mostly because we wanted to
give direct access to the sound hardware, without the
problems of high-level features — namely latency and
processor usage. We may add sample rate in future if we find
a good way to add it without affecting
performance.”
As an alternative, you can resample your data with a
sample rate converter to achieve the same effect. See also
How can I do sample rate
conversion? Or, you can still use the sample rate control of the
"Java Sound Audio Engine" with 1.5 by requesting lines
directly from it. See How can I get a
Line from a specific
Mixer? (Matthias) |
3. DataLine buffers |
- 3.1. What is the minimum buffer size
I can use?
- 3.2. Why does a line have the default buffer size though a
buffer size was specified in a
DataLine.Info object when obtaining
the line?
- 3.3. Why is it not possible to use large buffers for a
DataLine with 1.5.0?
| |
| 3.1. | What is the minimum buffer size
I can use? |
| Obviously, this depends on the operating system, the
hardware, the Java VM, which Mixer implementation you use
and several other factors. The following measurements have
been found experimentally on a very old PC (350 MHz) under
Linux with the Sun JDK 1.4.2_02: These measurements suggest that the latency introduced
by buffers in the "Java Sound Audio Engine" is about 50 ms,
independant of the sample rate. (Matthias) |
| 3.2. | Why does a line have the default buffer size though a
buffer size was specified in a
DataLine.Info object when obtaining
the line? |
| This happens with the "Direct Audio Device" of the JDK
1.5.0 if the line is opened with
open(AudioFormat) instead of
open(AudioFormat, int). The reason for
this behaviour is that by requiring a certain buffersize or
range of buffersizes in
DataLine.Info, you obtain a line that
is capable of setting its buffersize to
the respective value. You still have to choose the actual
value. This is done when opening the line: with
open(AudioFormat, int), a certain
buffer size for the line can be specified. If
open(AudioFormat) is used, the line is
opened with the default buffer size. Until 1.4.2, a
buffersize in DataLine.Info was used
in opening if the open() call does not
specify a buffer size. However, it was decided that
automatically taking over this value is a questionable
convenience. (Matthias) |
| 3.3. | Why is it not possible to use large buffers for a
DataLine with 1.5.0? |
| The DataLine implementation of
the "Java Sound Audio Engine" has a circular buffer per line
instance. For SourceDataLine
instances, write() writes data to this
buffer. A separate thread reads from the circular buffer and
transfers the data to the native layer of the engine. This
allows for arbitrary sized buffers, but results in the
overhead of an additional buffer and one thread per
DataLine. The DataLine implementation of
the "Direct Audio Device" of 1.5.0 does not have a circular
buffer. Instead, it writes/reads data directly to/from the
soundcard driver. This gives higher performance and lower
latency. On the other hand, it restricts buffer sizes to
what the soundcard driver supports. Adding a layer of buffering to the "Direct Audio
Device" mixers would result in the same performance penalty
as the DataLine implementation of the
"Java Sound Audio Engine". It would introduce a general
overhead though the additional functionality is only needed
in special cases. Therefore, it is unlikely that the
implementation of the "Direct Audio Device" mixers will be
changed to allow larger buffers. If you need larger buffers, you can implement an
additional layer with a circular buffer in your
application. Then you can choose any size you want for this
buffer. And note that you need an additional thread —
like the "Java Sound Audio Engine". The Answering Machine has
classes that do a similar job. There is also the class
org.tritonus.share.TCircularBuffer in
Tritonus that
you can use for this purpose. (Matthias) |
4. Mixers |
- 4.1. What are all these mixers?
- 4.2. Why are there mixers from
which I can't get a
SourceDataLine?
- 4.3. How can I redirect sound output to
a phone / modem device?
- 4.4. Can I use multiple soundcards at the same time?
- 4.5. Why can I record from
different soundcards, but not play back to them?
- 4.6. How can I obtain the formats
supported by a mixer (or at all)?
- 4.7. What formats are supported by "Direct Audio Device"
mixers?
- 4.8. Why are there
AudioFormat objects with frame
rate/sample rate reported as -1 when I
query a Mixer for its supported
formats?
- 4.9. How can I detect which Port
Mixer belongs to which soundcard?
- 4.10. How can I find out which
Mixer implementation is used?
- 4.11. Why do I get lines from the
"Java Sound Audio Engine" in the JDK 1.5.0 though the
"Direct Audio Device" mixers are available, too?
| |
| 4.1. | What are all these mixers? |
| There are several implementations of
Mixer in Java Sound: - "Java Sound Audio Engine", beatnik engine
This is a software mixing engine. It provides
SourceDataLine and
Clip instances. It does not
provide TargetDataLine
instances. Output of this mixer goes to the audio
device. In versions up to 1.4.2, this mixer is the
default for playback. In 1.5, it is only used if there
is no other way to mix audio streams (because neither
the soundcard hardware nor the device driver support
mixing). - Simple Input Devices, "Microsoft Sound Mapper" (Windows), "Linux,dev/dsp,multi threaded" (Linux), "Linux,dev/audio,multi threaded" (Linux, Solaris)
In versions 1.4.2 and earlier, this mixer is
used for recording. It provides
TargetDataLine instances, but
nothing else. In 1.5, it is no longer available,
because the direct audio devices can be used for
recording on all platforms. - Direct Audio Devices, "Primary Sound Driver" (Windows), "Primary Sound Capture Driver" (Windows), "Soundcard [plughw:0,0]" (Linux)
These are mixers that can be used for playback
as well as for recording. They provide
SourceDataLine,
TargetDataLine and
Clip instances. In 1.4.2, they
became available on Linux; in 1.5, Solaris and Windows
followed. These mixers allow simultaneous playback and
recording (full-duplex) if the soundcard supports
it. These mixers do not do software mixing. So mixing
of multiple playback lines is only available if either
the soundcard hardware or the device driver are
capable of mixing. In other words: You may get only
one SourceDataLine, and you
will always get only one
TargetDataLine - Port Mixers, "Port Soundcard" (Windows), "Port Soundcard [hw:0,0]" (Linux)
These mixers provide Port
instances, but no other type of Line. So you can't
play back or record with these mixers. They became
available with 1.4.2 for Windows, and will be
available for Solaris and Linux, too, in 1.5. See also
Ports
Note that what Java Sound calls "Mixer" is different
from what Windows calls "Mixer": See also How can I find out which
Mixer implementation is used? (Matthias) |
| 4.2. | Why are there mixers from
which I can't get a
SourceDataLine? |
| There are mixer that only provide
TargetDataLine instances. In the Sun
JDK up to 1.4.2, SourceDataLine
instances are only provided by the "Java Sound Audio
Engine", while TargetDataLine
instances are only provided by the "Simple Input Device"
mixers. This is subject to change for JDK 1.5. Starting with version 1.4.2, there are additional
mixers that provide only Port
instances. See also What are all these mixers? (Matthias) |
| 4.3. | How can I redirect sound output to
a phone / modem device? |
| With the Sun JDK 1.4.2 or earlier on Windows, you can
set the default audio device to the telephone device:
Control panel -> Multimedia (or Sounds...) ->
Preferred Device. With the "Direct Audio Device" mixers of
the JDK 1.5 it is also possible to use the default provider
properties to set the default Mixer /
MixerProvider inside Java
Sound. See also Why are there mixers from
which I can't get a
SourceDataLine?, How can I capture from a
specific source (microphone or line-in)?, How can I get a
Line from a specific
Mixer? and Why can I record from
different soundcards, but not play back to them? (Matthias) |
| 4.4. | Can I use multiple soundcards at the same time? |
| For the Sun JDK, this is possible with version 1.4.2
and later for Linux and with version 1.5.0 and later for
Solaris and Windows. For Tritonus, this is possible with the
ALSA Mixer
implementation. (Matthias) |
| 4.5. | Why can I record from
different soundcards, but not play back to them? |
| This is true for Solaris and Windows for Java versions
up to 1.4.2. There, playback is only possible via the "Java
Sound Audio Engine", which always uses the first
soundcard. On the other hand, recording in these versions is
done with the "Simple Input Device", which provider one
Mixer instance per soundcard. With the "Direct Audio Device" mixers, it is possible
to choose different soundcards for output, too. See also
What are all these mixers? (Matthias) |
| 4.6. | How can I obtain the formats
supported by a mixer (or at all)? |
| First, obtain a list of supported lines either from a
Mixer object or from
AudioSystem. For this, use the
methods getSourceLineInfo() and
getTargetLineInfo(). Then, check each
of the returned Line.Info objects if
it is an instance of
DataLine.Info. If it is, cast the
object to DataLine.Info. Now you can
call getFormats() to obtain the
AudioFormat types supported by this
line type. A code example:
Line.Info[] infos = AudioSystem.getSourceLineInfo();
// or:
// Line.Info[] infos = AudioSystem.getTargetLineInfo();
for (int i = 0; i < infos.length; i++)
{
if (infos[i] instanceof DataLine.Info)
{
DataLine.Info dataLineInfo = (DataLine.Info) infos[i];
AudioFormat[] supportedFormats = dataLineInfo.getFormats();
}
}To see what is supported on your system, you can use
the application jsinfo. See also Why are there
AudioFormat objects with frame
rate/sample rate reported as -1 when I
query a Mixer for its supported
formats?
(Matthias) |
| 4.7. | What formats are supported by "Direct Audio Device"
mixers? |
| It depends on the hardware. The mixers just report
formats that are supported by the device driver. Typically,
there are between 8 and 20 supported formats. To write a
portable application, you should not assume that a certain
format is always supported (though in fact, 44.1 kHz 16 bit
stereo is almost always supported). Rather, you should check
the supported formats at run-time and try to convert your
audio data to one of the available formats. See also How can I obtain the formats
supported by a mixer (or at all)?
(Matthias) |
| 4.8. | Why are there
AudioFormat objects with frame
rate/sample rate reported as -1 when I
query a Mixer for its supported
formats? |
| The -1
(AudioSystem.NOT_SPECIFIED) means that
any reasonable sample rate is supported. Common soundcards
typically support sample rates between 4 kHz and 48 kHz. See
also How can I obtain the formats
supported by a mixer (or at all)? (Matthias) |
| 4.9. | How can I detect which Port
Mixer belongs to which soundcard? |
| There is no really satisfying solution. You can try to
match the name in the
Mixer.Info object of a Port Mixer
against the one of a DataLine Mixer. On Linux, this is
reliable by looking at the device id that is part of the
mixer name: "(hw:0)", "(hw:1)", "(plughw:0,1)". The first
(or only) number refers to the number of the
soundcard. Windows don't allow to query which port belongs to
which soundcard (there are ways on Windows, but it was not
possible to use them for Java Sound because they require
actually opening the devices). So the only thing you can do
is to match the name of the soundcard. However, this will
not always work reliably. Especially, if there are two
soundcards of the same model, their names will look the
same. See also What are all these mixers? (Matthias) |
| 4.10. | How can I find out which
Mixer implementation is used? |
| You can detect the mixer implementation from the class
types of the lines you get: See also What are all these mixers?
and How can I find out which
soundcard driver is used? (Matthias) |
| 4.11. | Why do I get lines from the
"Java Sound Audio Engine" in the JDK 1.5.0 though the
"Direct Audio Device" mixers are available, too? |
| In the JDK 1.5.0, the "Direct Audio Device" mixers are
used by default if they support more than one concurrently
active SourceDataLine. This is the
case if either the soundcard hardware supports mixing of
multiple channels (and the driver supports it) or the driver
does software mixing of multiple channels. If this is not the case, the "Java Sound Audio Engine"
is used by default. If you don't mind the limitation that
there will be only one SourceDataLine
or Clip instance, you can still use
the "Direct Audio Device" mixers by addressing them directly
(see How can I get a
Line from a specific
Mixer?). See also Can I make ALSA the default in
version 1.4.2? and How can I enable mixing with the
"Direct Audio Device" mixers on Linux? (Matthias) |
5. Soundcard Drivers |
- 5.1. Which soundcard drivers
can be used by Java Sound?
- 5.2. How can I find out which
soundcard driver is used?
- 5.3. I've installed ALSA and the JDK 1.4.2 to take
advantage of the ALSA support. Now, how do I use it?
- 5.4. Can I make ALSA the default in
version 1.4.2?
- 5.5. How can I enable mixing with the
"Direct Audio Device" mixers on Linux?
- 5.6. What are the requirements for using the direct audio
devices?
- 5.7. How can I find out which
soundcard driver is installed on my Linux system?
- 5.8. How does Java Sound deal with
hardware buffers of the soundcard?
| |
| 5.1. | Which soundcard drivers
can be used by Java Sound? |
| See also What are all these mixers?
and Q: 3.5
(Matthias) |
| 5.2. | How can I find out which
soundcard driver is used? |
| First, check which mixer is used (see How can I find out which
Mixer implementation is used?). Then consult the table in
Which soundcard drivers
can be used by Java Sound? to find out the
driver. For Linux, there is no way to tell from Java Sound if
a real OSS driver or ALSA's OSS emulation is used. See also
How can I find out which
soundcard driver is installed on my Linux system? (Matthias) |
| 5.3. | I've installed ALSA and the JDK 1.4.2 to take
advantage of the ALSA support. Now, how do I use it? |
| In 1.4.2, the "Java Sound Audio Engine" is still the
default. To use the ALSA support, you have to obtain the
Mixer object representing the direct audio access. Then,
obtain lines from this object instead of via
AudioSystem. See also How can I get a
Line from a specific
Mixer?
(Matthias) |
| 5.4. | Can I make ALSA the default in
version 1.4.2? |
| You can, but only with an ugly trick: rename, remove
or disable the device files
/dev/dsp*. This disables the Java Sound
Audio Engine, so the JDK falls back to use the ALSA
mixers. But be aware that this disables the software
synthesizer ("Java Sound Synthesizer"), too. So you won't be
able to play MIDI files. And of course native applications
using /dev/dsp won't be happy,
too. (Matthias) |
| 5.5. | How can I enable mixing with the
"Direct Audio Device" mixers on Linux? |
| The "Direct Audio Device" implementation on Linux is
based on ALSA. Mixing is
available in the Mixer instance if
ALSA provides mixing. This is the case if the soundcard can
do mixing in hardware and its ALSA driver supports this
feature. This is true for some common soundcards like
Soundblaster LIFE! and Soundblaster Audigy and cards based
on the Trident 4D Wave NX chipset. If this feature is
available at all, it needs no special configuration. It is
enabled by default. Using ALSA's dmix
plug-in does not work together with Java Sound. The
reason is that the "Direct Audio Device" mixer
implementation based on ALSA queries the available hardware
devices. However, a dmix device in ALSA is no hardware
device, so it is not recognized. Discussions about this
issue led to the conclusion that there is no easy way to
integrate a query for additional devices. See also Q: 3.4 (Matthias) |
| 5.6. | What are the requirements for using the direct audio
devices? |
| According to Florian: (Matthias) |
| 5.7. | How can I find out which
soundcard driver is installed on my Linux system? |
| Run /sbin/lsmod to show the
currently loaded kernel modules. If there are entries "snd"
and "snd-*", you are running ALSA. A typical picture of ALSA
is like this:
snd-mixer-oss 12672 1 (autoclean) [snd-pcm-oss]
snd-seq 38348 0 (autoclean) (unused)
snd-emu10k1 65956 1 (autoclean)
snd-hwdep 5024 0 (autoclean) [snd-emu10k1]
snd-rawmidi 13792 0 (autoclean) [snd-emu10k1]
snd-pcm 64416 0 (autoclean) [snd-pcm-oss snd-emu10k1]
snd-page-alloc 6148 0 (autoclean) [snd-emu10k1 snd-pcm]
snd-timer 15040 0 (autoclean) [snd-seq snd-pcm]
snd-ac97-codec 42200 0 (autoclean) [snd-emu10k1]
snd-seq-device 4116 0 (autoclean) [snd-seq snd-emu10k1 snd-rawmidi]
snd-util-mem 1504 0 (autoclean) [snd-emu10k1]
snd 36832 0 (autoclean) [snd-pcm-oss snd-mixer-oss snd-seq
snd-emu10k1 snd-hwdep snd-rawmidi snd-pcm snd-timer snd-ac97-codec
snd-seq-device snd-util-mem]
soundcore 3556 6 (autoclean) [snd]
An alternative way it to look for the directory
/proc/asound/. It is only present if
ALSA is active. (Matthias) |
| 5.8. | How does Java Sound deal with
hardware buffers of the soundcard? |
| Internally, Java Sound implementations usually do not
work with hardware buffers. Instead, they use the platform's
audio API for accessing the soundcard. See also DataLine buffers
(Matthias) |
6. Synchronization |
- 6.1. How can I synchronize two or more
playback lines?
- 6.2. How can I synchronize playback
(SourceDataLines) with recording (TargetDataLines)?
- 6.3. How can I synchronize
playback to an external clock?
- 6.4. Do multiple
Clip instances that are looped stay
in sync?
- 6.5. Why does recording or playing for a
certain period of time results in audio data that is shorter
or longer than the period I recorded / played?
- 6.6. How can I use
Mixer.synchronize()?
| |
| 6.1. | How can I synchronize two or more
playback lines? |
| The synchronization functions in
Mixer are not
implemented. Nevertheless, playback typically stays in
sync. (Matthias) |
| 6.2. | How can I synchronize playback
(SourceDataLines) with recording (TargetDataLines)? |
| As with multiple playback lines from the same
Mixer object, playback and recording
lines from the same Mixer object stay
in sync once they are started. In practice, this means that
you can achieve synchronization this easy way only by using
the "Direct Audio Device" mixers. Since the "Java Sound
Audio Engine" only provides playback lines, but no recording
lines, playback/recording sync is not as easy with the "Java
Sound Audio Engine". See also How can I synchronize two or more
playback lines? If playback and recording lines originate from
different Mixer objects, you need to
synchronize the soundcards that are represented by the
Mixer objects. So the situation is
similar to external synchronization. See also How can I synchronize
playback to an external clock? (Matthias) |
| 6.3. | How can I synchronize
playback to an external clock? |
| This is possible in one of two ways: See also Q: 3.12 (Matthias) |
| 6.4. | Do multiple
Clip instances that are looped stay
in sync? |
| Yes. There is no mechanism in Java Sound to start
Clip instances
synchronuously. However, calling
start() for all
Clip instances in a loop with the
Clip instances otherwise prepared
should be precise enough. Once started,
Clip instances played on the same
Mixer instance should stay in
sync. If they don't, make sure they have the exactly same
length. Clip instances played on
different Mixer instance are likely
to drift away from each other, unless the soundcard clocks
are synchronized (which is only possible on "pro"
soundcards). (Matthias) |
| 6.5. | Why does recording or playing for a
certain period of time results in audio data that is shorter
or longer than the period I recorded / played? |
| The reason of this problem is clock drift. There are
two clocks involved in this scenario: The real
time clock is used to measure the period of time
you are recording or playing. The soundcard
clock determine how many samples are recorded or
played during this period. Since there are two different
hardware devices, the inherently drift away from each other
over time. There are several ways to deal with this
problem: You can try to minimize the drift by
making both clocks high-precision. The real-time clock of
the computer can be synchronized to atomic clocks by using
some means of synchronization. The Network Time Protocol
(NTP) is commonly used for this on the internet. On
Windows, the utility AboutTime
can be used for synchronization. The precision of the
soundcard clock can be enhanced by using a professional
soundcard with a "word clock" input. This input has to be
connected to an external high-precision time base. In this
case, the soundcard clock is synchronized to the external
clock source. Professional studios often spend tens of
thousands of dollars to purchase a high-precision time
base. Note that this solution minimizes the drift, but
cannot remove it completely. You can use the soundcard clock as your
time base to measure wall-clock time. This way, you have
removed the second clock, so there is no drift. While this
may sound inconvenient, it may be a good solution if the
audio data has to be synchronized to, for instance, video
playback or the playback of slides, mouse events or
MIDI. If your soundcard's clock is synchronized to an
external time base as described in the previous point,
using it to measure wall-clock time is likely to give much
better results than using the computer's (unsynchronized)
"real time" clock. If both of the above solutions are not
appropriate, you can adapt the length of the audio data by
doing time streching/shrinking. This usually requires
fairly advanced and computationally expensive DSP
algorithms. In this case, you do not remove the clock
drift, but remove the effect of it on your audio
data.
(Matthias) |
| 6.6. | How can I use
Mixer.synchronize()? |
| Synchronization isn't implemented in any known Java
Sound implementation. It may be implemented in future
versions. Note that you can check the availability of
synchronization with the method Mixer.isSynchronizationSupported(). See
also Do multiple
Clip instances that are looped stay
in sync?,
How can I synchronize two or more
playback lines?
and Why does recording or playing for a
certain period of time results in audio data that is shorter
or longer than the period I recorded / played?
(Matthias) |
7. Audio Files |
- 7.1. How can I save audio data to a file, like
.wav or
.aiff?
- 7.2. How can I add special chunks to
.wav or .aiff
files (like for a descriptive text or copyright)?
- 7.3. Is it possible to get
information about loop points (e.g. from the 'smpl' chunk in
.wav files) using the
AudioFileFormat properties?
- 7.4. Why does
AudioFileFormat.getFrameLength() always
return -1 for .wav
files?
- 7.5. Why does a .wav file contain
PCM_UNSIGNED data if I try to save 8
bit PCM_SIGNED data?
- 7.6. How can I read in a .vox file and
save it as .wav file?
- 7.7. How can I read from a headerless audio file?
- 7.8. How can I determine the length or
the duration of an audio file?
- 7.9. How can I write an audio file in
smaller parts?
- 7.10. Why are some .wav files not
recognized by Java Sound?
- 7.11. Why is it not possible to write big-endian data using
a WaveAudioOutputStream?
- 7.12. How can I edit or modify audio files?
- 7.13. How can I play audio files where the data is cached in
the RAM?
- 7.14. Why is there a difference between using
AudioSystem.write(..., File) and using
AudioSystem.write(..., OutputStream)
with a FileOutputStream?
- 7.15. Where can I find documentation on the
AudioOutputStream programming?
- 7.16. How can I start playback of a file at a certain
position?
- 7.17. Is it possible to read and
write multichannel audio files?
- 7.18. How can I compare two audio
files?
- 7.19. Is it possible to insert
recorded audio data into an existing file?
- 7.20. How can I store an audio file
in a byte array?
- 7.21. Which value should I use for
the length of the file in
AudioOutputStreams if the length is
not known in advance?
| |
| 7.1. | How can I save audio data to a file, like
.wav or
.aiff? |
| Have a look at the Java Sound Resources: Examples. (Florian) |
| 7.2. | How can I add special chunks to
.wav or .aiff
files (like for a descriptive text or copyright)? |
| The Java Sound API does not support this
currently. Future versions are likely to, because this is
indeed quite important. For the moment, you will need to
implement your own class for writing
.wav or .aiff
files. Or make meaningful filenames... (Florian) |
| 7.3. | Is it possible to get
information about |