Edit: I found a solution by changing just a few lines, problem was only partly due to bad loops. This was the bulk of the issue:
'''
public void recordStop(){
System.out.println("stop recording");
recordingRunning = false;
if (dataLine != null) {
dataLine.flush();
dataLine.close();
System.out.println("close and drain line");
}
}
'''
using .drain() kills the thread so just used .flush() instead and we chilling.
(TLDR - when I press a button to drain a target data line, the function called will try to drain the line in but the GUI will crash and no file is output)
I've been making an audio recorder with JavaFXML, using the java sound sampled class. I'm using a separate thread to run the recorder while the GUI is running but the issue comes when trying to stop the recording and save the recording. I've managed to get the thread to start okay and run on a button press. This is activated by this code:
The FXML event handler when button is pressed:
'''
@FXML
private void recordingButtonAction(ActionEvent event) throws LineUnavailableException {
if(isRecording == false){
label.setText("Recording");
fileName = RT.setFileName();
channelLocationTracker(channelSelectToggleGroup);
try{
TargetDataLine dataLine =AudioSystem.getTargetDataLine(audioFormat);
}
catch (LineUnavailableException ex) {
ex.printStackTrace();
}
isRecording=true;
}
else{
System.out.println("Already recording");
}
}
'''
The code to start recording in seperate class where object "RT" comes from:
'''
public TargetDataLine getDataLine() throws LineUnavailableException{
audioFormat = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
if (!AudioSystem.isLineSupported(info)) {
throw new LineUnavailableException(
"Format Unsupported");
}
final TargetDataLine dataLine = AudioSystem.getTargetDataLine(audioFormat);;
AudioSystem.getLine(info);
return dataLine;
}
''' '''
public void recordStart(boolean isRecording) throws LineUnavailableException{
isRecording = false;
audioFormat = getAudioFormat();
dataLine = getDataLine();
dataLine.open(audioFormat);
dataLine.start();
System.out.println("open line");
System.out.println("start recording");
byte[] buffer = new byte[bufferSz];
int bytesRead = 0;
recordedBytes = new ByteArrayOutputStream();
isRecording = true;
while (isRecording) {
bytesRead = getDataLine().read(buffer, 0, buffer.length);
recordedBytes.write(buffer, 0, bytesRead);
}
}
'''
And the thread itself:
'''
private void startRecord(){
Thread startRec = new Thread(new Runnable(){
public void run(){
try {
isRecording=true;
RT.recordStart(isRecording);
} catch (LineUnavailableException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
startRec.start();
}
'''
Issue arises when I press the stop recording button, it will print drain line in the shell but the GUI will crash and recording stopped will not be printed. I think the issue comes from the .drain() method.
Once again here's the FXML:
'''
@FXML
private void stopButtonAction(ActionEvent event) throws IOException, LineUnavailableException,
UnsupportedAudioFileException {
RT.setFileName("recording"+".wav");
recordedFileWAV = RT.getFile();
if(isRecording == true){
endRecord();
}
}
'''
Separate class for stopping recording:
'''
public void recordStop(boolean isRecording){
isRecording = false;
System.out.println("drain line");
dataLine.drain();
System.out.println("stop recording");
dataLine.close();
}
'''
And the method in the recording class which let's you save:
'''
public void recordSave(File wavFile) throws IOException {
byte[] lineData = recordedBytes.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(lineData);
AudioInputStream AIS = new AudioInputStream(bais, audioFormat,lineData.length /
audioFormat.getFrameSize());
AudioSystem.write(AIS, AudioFileFormat.Type.WAVE, wavFile);
AIS.close();
recordedBytes.close();
}
Please let me know if you can figure out what's going wrong or if you can point me in the right direction :)