I have a problem connected with my previous question. I want to record audio from mixer (speakers), I\'m using javax.sound. I have to set up audioFormat and I don\'t know wh
It is possible to obtain all supported Lines
and their AudioFormats
directly. I did this for the SourceDataLines
of the default Mixer
on the system, and you can easily edit the code to get any type of Lines
and AudioFormats
supported by any Mixer
.
Mixer mixer = AudioSystem.getMixer(null); // default mixer
mixer.open();
System.out.printf("Supported SourceDataLines of default mixer (%s):\n\n", mixer.getMixerInfo().getName());
for(Line.Info info : mixer.getSourceLineInfo()) {
if(SourceDataLine.class.isAssignableFrom(info.getLineClass())) {
SourceDataLine.Info info2 = (SourceDataLine.Info) info;
System.out.println(info2);
System.out.printf(" max buffer size: \t%d\n", info2.getMaxBufferSize());
System.out.printf(" min buffer size: \t%d\n", info2.getMinBufferSize());
AudioFormat[] formats = info2.getFormats();
System.out.println(" Supported Audio formats: ");
for(AudioFormat format : formats) {
System.out.println(" "+format);
// System.out.printf(" encoding: %s\n", format.getEncoding());
// System.out.printf(" channels: %d\n", format.getChannels());
// System.out.printf(format.getFrameRate()==-1?"":" frame rate [1/s]: %s\n", format.getFrameRate());
// System.out.printf(" frame size [bytes]: %d\n", format.getFrameSize());
// System.out.printf(format.getSampleRate()==-1?"":" sample rate [1/s]: %s\n", format.getSampleRate());
// System.out.printf(" sample size [bit]: %d\n", format.getSampleSizeInBits());
// System.out.printf(" big endian: %b\n", format.isBigEndian());
//
// Map<String,Object> prop = format.properties();
// if(!prop.isEmpty()) {
// System.out.println(" Properties: ");
// for(Map.Entry<String, Object> entry : prop.entrySet()) {
// System.out.printf(" %s: \t%s\n", entry.getKey(), entry.getValue());
// }
// }
}
System.out.println();
} else {
System.out.println(info.toString());
}
System.out.println();
}
mixer.close();
I get an output like this:
interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes
max buffer size: -1
min buffer size: 32
Supported Audio formats:
PCM_UNSIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
PCM_SIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, little-endian
PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, big-endian
PCM_UNSIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
PCM_SIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, little-endian
PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian
interface Clip supporting 8 audio formats, and buffers of at least 32 bytes
You're getting a TargetDataLine using an AudioFormat you've created. This isn't guaranteed to work. You must first query the Mixer to check if it supports your desired AudioFormat using the AudioSystem.isLineSupported(Info info)
method.
Personally, I find this quite cumbersome. You need to query the Mixers on the system to determine if they support the AudioFormat you want.
The function below will get a Vector of supported formats for a data line class. Call it using
Vector<AudioFormat> formats = getSupportedFormats(TargetDataLine.class);
or
Vector<AudioFormat> formats = getSupportedFormats(SourceDataLine.class);
This code might need a bit of debugging; I had to remove some of my app-specific stuff to make it self contained...
public Vector<AudioFormat> getSupportedFormats(Class<?> dataLineClass) {
/*
* These define our criteria when searching for formats supported
* by Mixers on the system.
*/
float sampleRates[] = { (float) 8000.0, (float) 16000.0, (float) 44100.0 };
int channels[] = { 1, 2 };
int bytesPerSample[] = { 2 };
AudioFormat format;
DataLine.Info lineInfo;
SystemAudioProfile profile = new SystemAudioProfile(); // Used for allocating MixerDetails below.
Vector<AudioFormat> formats = new Vector<AudioFormat>();
for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) {
for (int a = 0; a < sampleRates.length; a++) {
for (int b = 0; b < channels.length; b++) {
for (int c = 0; c < bytesPerSample.length; c++) {
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
sampleRates[a], 8 * bytesPerSample[c], channels[b], bytesPerSample[c],
sampleRates[a], false);
lineInfo = new DataLine.Info(dataLineClass, format);
if (AudioSystem.isLineSupported(lineInfo)) {
/*
* TODO: To perform an exhaustive search on supported lines, we should open
* TODO: each Mixer and get the supported lines. Do this if this approach
* TODO: doesn't give decent results. For the moment, we just work with whatever
* TODO: the unopened mixers tell us.
*/
if (AudioSystem.getMixer(mixerInfo).isLineSupported(lineInfo)) {
formats.add(format);
}
}
}
}
}
}
return formats;
}