since there is no easy way in java to access the systems microphones and speakers I tried to implement something like that my self. For this I have a class AudioDevice
representing any device.
It is a abstract class defining all method a audiodevice needs and is based on a javax.sound.sampled.Mixer
. Then I have the classes Microphone
and Speaker
which are extending from AudioDevice
and are implementing the abstract methods of AudioDevice
. Such as transferData(byte[])
, open(AudioFormat)
, isOpen()
and close()
.
When i run my testcode it seems to work since no error are occuring. But for some reason the transferData(byte[])
of my microphone isn't writing any data to the array. If I use a prefilled byte[] and i use it as a parameter for the transferData(byte[])
of my speaker, the speaker isn't playing any sound either.
I've spend multiple hours on searching the error causing this problem and I've also tried to capture/play sound like it is discribed here and it didn't work on my computer either.
I have got a Windows Professional N 64-Bit OS if that could be a reason why it isnt working. The Programm is running with Java 8.
This is the code i've come up with
AudioDevice:
public abstract class AudioDevice<E> {
private final static Set<AudioFormat> AUDIO_FORMATS = new HashSet<>();
static {
final float[] sampleRates = new float[] { 8000.0F, 11025.0F, 16000.0F, 22050.0F, 44100.0F };
final int[] sampleSizes = new int[] { 8, 16 };
final int[] channels = new int[] { 1, 2 };
for (final float sampleRate : sampleRates) {
for (final int sampleSize : sampleSizes) {
for (final int channel : channels) {
final AudioFormat bigEndian_signed = new AudioFormat(sampleRate, sampleSize, channel, true, true);
final AudioFormat bigEndian_unsigned = new AudioFormat(sampleRate, sampleSize, channel, false,
true);
final AudioFormat littleEndian_signed = new AudioFormat(sampleRate, sampleSize, channel, true,
false);
final AudioFormat littleEndian_unsigned = new AudioFormat(sampleRate, sampleSize, channel, false,
false);
AUDIO_FORMATS.add(littleEndian_unsigned);
AUDIO_FORMATS.add(bigEndian_unsigned);
AUDIO_FORMATS.add(bigEndian_signed);
AUDIO_FORMATS.add(littleEndian_signed);
}
}
}
}
protected final Mixer mixer;
private final Mixer.Info mixerInfo;
private final Class<E> lineType;
private final Set<AudioFormat> supportedFormats = new HashSet<>();
protected AudioFormat currentFormat;
protected E currentDataLine;
public AudioDevice(final Mixer pMixer, final Class<E> pLineType) {
if (pMixer == null) {
throw new IllegalArgumentException();
}
this.mixer = pMixer;
this.mixerInfo = pMixer.getMixerInfo();
this.lineType = pLineType;
loadSupportedFormats(pLineType);
if (this.supportedFormats.isEmpty()) {
throw new IllegalArgumentException();
}
}
public abstract boolean transferData(final byte[] pBuffer);
public abstract boolean open(final AudioFormat pFormat);
public abstract boolean isOpen();
public abstract boolean close();
public final boolean isUsingFormat(final AudioFormat pFormat) {
if (isOpen() && this.currentFormat != null) {
return this.currentFormat.equals(pFormat);
}
return false;
}
public final Set<AudioFormat> getSupportedFormats() {
return this.supportedFormats;
}
public final AudioFormat getCurrentFormat() {
return this.currentFormat;
}
public final boolean isFormatSupported(final AudioFormat pFormat) {
if (pFormat != null) {
final Set<AudioFormat> supportedFormats = getSupportedFormats();
if (supportedFormats != null) {
final DataLine.Info info = new Info(this.lineType, pFormat);
return this.mixer.isLineSupported(info);
}
}
return false;
}
public final String getName() {
return this.mixerInfo.getName();
}
public final String getDescription() {
return this.mixerInfo.getDescription();
}
public final String getVendor() {
return this.mixerInfo.getVendor();
}
public final String getVersion() {
return this.mixerInfo.getVersion();
}
private final void loadSupportedFormats(final Class<E> pLineType) {
for (final AudioFormat format : AUDIO_FORMATS) {
final DataLine.Info info = new Info(pLineType, format);
if (this.mixer.isLineSupported(info)) {
this.supportedFormats.add(format);
}
}
}
}
Microphone:
public final class Microphone extends AudioDevice<TargetDataLine> {
public Microphone(final Mixer pMixer) {
super(pMixer, TargetDataLine.class);
}
@Override
public final boolean transferData(final byte[] pBuffer) {
if (isOpen()) {
this.currentDataLine.read(pBuffer, 0, pBuffer.length);
return true;
}
return false;
}
@Override
public final boolean open(final AudioFormat pFormat) {
if (!isOpen() && isFormatSupported(pFormat)) {
try {
this.mixer.open();
final DataLine.Info info = new Info(TargetDataLine.class, pFormat);
this.currentDataLine = (TargetDataLine) this.mixer.getLine(info);
this.currentFormat = pFormat;
return true;
} catch (final LineUnavailableException e) {
close();
return false;
}
}
return false;
}
@Override
public final boolean isOpen() {
return this.mixer.isOpen() && this.currentDataLine != null;
}
@Override
public final boolean close() {
if (isOpen()) {
this.currentDataLine.close();
this.mixer.close();
this.currentDataLine = null;
this.currentFormat = null;
return true;
}
this.currentDataLine = null;
this.currentFormat = null;
return false;
}
}
Speaker:
public final class Speaker extends AudioDevice<SourceDataLine> {
public Speaker(final Mixer pMixer) {
super(pMixer, SourceDataLine.class);
}
@Override
public final boolean transferData(final byte[] pBuffer) {
if (isOpen()) {
this.currentDataLine.write(pBuffer, 0, pBuffer.length);
return true;
}
return false;
}
@Override
public final boolean open(final AudioFormat pFormat) {
if (!isOpen() && isFormatSupported(pFormat)) {
try {
this.mixer.open();
final DataLine.Info info = new Info(SourceDataLine.class, pFormat);
this.currentDataLine = (SourceDataLine) this.mixer.getLine(info);
this.currentFormat = pFormat;
return true;
} catch (final LineUnavailableException e) {
close();
return false;
}
}
return false;
}
@Override
public final boolean isOpen() {
return this.mixer.isOpen() && this.currentDataLine != null;
}
@Override
public final boolean close() {
if (isOpen()) {
this.currentDataLine.close();
this.mixer.close();
this.currentDataLine = null;
this.currentFormat = null;
return true;
}
this.currentDataLine = null;
this.currentFormat = null;
return false;
}
}