public class captureAudio{
IMediaWriter writerAudio=null;
long currentAudioTime;
void startAudio() throws Exception {
TargetDataLine line;
//gets a TargetDataLine in which gets data from the Microphone
line= getMic();
//creates an array that is half the data buffer so that we don't have to worry about sample discards
final byte[] audioBytes=new byte[line.getBufferSize()/2];
final String outputFilename = "c:/Users/NICK/Desktop/SaveJPEG/"+"saved"+".aac";
//creates a writer in which it's output is to outputFilename
writerAudio = ToolFactory.makeWriter(outputFilename);
//starts I/O process in which starts capturing
line.start();
//gets current system time in nanoseconds
currentAudioTime = System.nanoTime();
//sets audioRunning to true
setstopper(true);
writerAudio.addAudioStream(0, 0,ICodec.ID.AV_CODEC_ID_AAC, 1, 44100);
//create new thread in which audio will be captured and encoded
Thread thread = new Thread() {
@Override
public void run() {
while(audioRunning()) {
short[] audioSamples;
int numSamplesRead=0;
int numBytesRead=0;
//get the number of bytes read
numBytesRead=line.read(audioBytes,0,audioBytes.length);
numSamplesRead=numBytesRead/2;
//create an array with a size of numSamplesRead. It is smaller than numBytesRead since we
//have 16 bit of data in each index of this array
audioSamples = new short[numSamplesRead];
/*Since the IMediaWriter.encodeAudio method takes in a short array,
We need to convert byte array to a short*/
//checks to see if the format is bigEndian or littleEndian which is indeed littleEndian by the format
if(line.getFormat().isBigEndian()) {
for (int i = 0; i < numSamplesRead; i++) {
audioSamples[i] = (short)((audioBytes[2*i] << 8) | audioBytes[2*i + 1]);
}
}
else {
/*cast to short, get 2nd element create 8 zeros to the right(making it 16 bit) and include the first element (still 8 bit)*/
for (int i = 0; i < numSamplesRead; i++) {
audioSamples[i] = (short)((audioBytes[2*i + 1] << 8) | audioBytes[2*i]);
}
}
//Stream index is 0, pass in short[] audioSamples, get sample timestamp, units of timestamp
writerAudio.encodeAudio(0, audioSamples,System.nanoTime()-currentAudioTime,TimeUnit.NANOSECONDS);
}
}
};
//starts the thread above
thread.start();
}
TargetDataLine getMic() throws Exception {
//Audioformat object that takes a sample rate,bit size per sample,channel, and bool isBigEndian
AudioFormat format = new AudioFormat(44100F,16,1,true,false);
TargetDataLine line =null;
DataLine.Info info = new DataLine.Info(TargetDataLine.class,format); // format is an AudioFormat object
if (!AudioSystem.isLineSupported(info)) {
throw new Exception();
}
void stop() throws Exception {
TargetDataLine mic = getMic();
setstopper(false);
mic.stop();
mic.close();
writerAudio.flush();
writerAudio.close();
}
}
Summary
The main idea is that I am trying to retrieve data from the microphone through a TargetDataLine and then am creating a new thread to run the encoding process of the audio along with the main thread which my videoCapture class uses to encode the video. Inside of the new thread, I am turning the audio samples array (originally a byte array) into a short array to use in the IMediaWriter.encodeAudio(...) method described above which the writer will successfully create a .acc audio file in my output file path.
Question
When I run the code I do get the desired audio file, but the audio quality is terrible. When I play back the audio, it is real staticky and choppy. So how exactly can I make the quality of the audio better?