I am trying to make Java play different stereo audio in two outputs (front and back audio jacks).
My sound card is configured as to treat both outputs independently, and in the Windows mixer I can make them emit a test sound separately, so it's not a card issue.
I tried the approach on Change Mixer to output sound to in java using different outputs by getting two Clips with different mixers, with AudioSystem.getClip(AudioSystem.getMixerInfo()[i]);
. However, this line of code works only with the Java Sound Audio Engine (AudioSystem.getMixerInfo()[0]
), which outputs in Windows' default audio output. Anything else throws
java.lang.IllegalArgumentException: Line unsupported: interface Clip supporting format PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian
The following example code generates a 5-second long white noise and plays it for 1 second and then finishes. It prints Mixer information as seen on how do I get Mixer channels layout in java. It currently outputs to the "Java Sound Audio Engine" Mixer, and trying to change to any other Mixer throws the exception above.
import java.io.ByteArrayInputStream;
import java.security.SecureRandom;
import java.util.Random;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.Line;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;
public class Main {
static int SAMPLE_RATE = 44100;
static AudioFormat format = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED, // Encoding
SAMPLE_RATE, // sample rate
8, // sample size in bits
2, // channels
4, // frame size
SAMPLE_RATE, // frame rate
true); // is big endian
static int DURATION = 5;
Thread soundThread;
// Noise audio
static AudioInputStream inputStream = new AudioInputStream(new ByteArrayInputStream(generateNoise(DURATION*2*SAMPLE_RATE)), format, DURATION*SAMPLE_RATE);
public static void main(String[] args) {
try {
// https://stackoverflow.com/questions/12863081/how-do-i-get-mixer-channels-layout-in-java
Mixer.Info[] mi = AudioSystem.getMixerInfo();
for (Mixer.Info info : mi) {
System.out.println("info: " + info);
Mixer m = AudioSystem.getMixer(info);
System.out.println("mixer " + m);
Line.Info[] sl = m.getSourceLineInfo();
for (Line.Info info2 : sl) {
System.out.println(" info: " + info2);
Line line = AudioSystem.getLine(info2);
if (line instanceof SourceDataLine) {
SourceDataLine source = (SourceDataLine) line;
DataLine.Info i = (DataLine.Info) source.getLineInfo();
for (AudioFormat format : i.getFormats()) {
System.out.println(" format: " + format);
}
}
}
System.out.println("");
}
// Code only works for AudioSystem.getMixerInfo()[0]
final Clip clip = AudioSystem.getClip(AudioSystem.getMixerInfo()[0]);
clip.open(inputStream);
Thread soundThread = new Thread(new Runnable() {
@Override
public void run() {
try {
clip.loop(Clip.LOOP_CONTINUOUSLY);
Thread.sleep(1000);
clip.close();
System.exit(0);
} catch (Exception e) {
e.printStackTrace();
}
}
});
soundThread.start();
} catch (Exception e) {
e.printStackTrace();
}
}
private static byte[] generateNoise(int size) {
byte[] out = new byte[size];
Random r = new SecureRandom();
r.nextBytes(out);
return out;
}
}
Here is the Mixer information. This code ran with both output jacks connected and Windows recognizes as two different output devices (speakers and headphones). It looks like only Java's audio engine can play sounds.
info: Java Sound Audio Engine, version 1.0
mixer com.sun.media.sound.HeadspaceMixer@22c84d9
info: interface SourceDataLine supporting 8 audio formats
format: PCM_SIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
format: PCM_UNSIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
format: PCM_SIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
format: PCM_UNSIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
format: PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, big-endian
format: PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, little-endian
format: PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian
format: PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, little-endian
info: interface Clip supporting 8 audio formats, and buffers of 0 to 4194304 bytes
info: Microsoft ?T?E???h, version Unknown Version
mixer com.sun.media.sound.SimpleInputDevice@7e0df503
info: Stereo Mixer (Realtek High Defi, version Unknown Version
mixer com.sun.media.sound.SimpleInputDevice@4650d89c
info: Port Realtek HD Audio 2nd output (Re, version 6.1
mixer com.sun.media.sound.PortMixer@65bd0dd4
info: Port Stereo Mixer (Realtek High Defi, version 6.1
mixer com.sun.media.sound.PortMixer@78b5f53a
info: ?}?X? source port
info: Port Speakers (Realtek High Definiti, version 6.1
mixer com.sun.media.sound.PortMixer@b37c60d
I am using Java 6 because of other limitations. Also, some names are broken probably because I'm in a Japanese environment and Eclipse won't fetch the names in the correct encoding (I've tried changing everything to UTF-8 and Shift_JIS but nothing changed, but I guess it's not related to this problem).
In other words, It looks like can't output in Clips from different Mixers because Java can only output to "Java Sound Audio Engine" which goes to Windows' default audio device. Is there any way to get the other Mixers to work? Is there an alternative to use multiple audio outputs?
Update: It seems like this problem was already fixed but I still can't get it to work. I disabled the "Stereo Mix" recording device and ran the example code given in that link, and got this output:
MIXER 0: Java Sound Audio Engine, version 1.0
OUTPUT LINE (SourceDataLine) 0: interface SourceDataLine supporting 8 audio formats
OUTPUT LINE (SourceDataLine) 1: interface Clip supporting 8 audio formats, and buffers of 0 to 4194304 bytes
MIXER 1: Port Realtek HD Audio 2nd output (Re, version 6.1
INPUT LINE (TargetDataLine) 0: HEADPHONE target port
MIXER 2: Port Speakers (Realtek High Definiti, version 6.1
INPUT LINE (TargetDataLine) 0: SPEAKER target port
So it looks like only Java Sound Audio Engine can output sound as both the mixers for the front and back audio jacks are treated as input lines. Played audio through either Clip or SourceDataLine outputs in the Windows' default playback device.
Also, it looks like they solved the problem by using DirectAudio but I still did not figure out how to use them.
While testing in different computers, I solved this problem by upgrading to Java 1.6.0_17 (which was still okay with my environment limitations to call Java from Matlab) so the DirectAudio drivers would be listed (even though it looks like it should work from Java 1.5). Each DirectAudio sound device gives a SourceDataLine and a Clip for each device.