package call; import java.io.BufferedOutputStream; import java.io.OutputStream; import java.net.SocketException; import java.util.ArrayList; import java.util.List; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.TargetDataLine; public class CallRecorder extends AbstractCallConnection implements Runnable { private final TargetDataLine line; private final OutputStream out; private final List<OutputStream> captureStreams = new ArrayList<>(); private long bytesSent = 0; public CallRecorder(Contact contact, OutputStream out) throws LineUnavailableException, UnknownDefaultValueException { super(contact); this.out = out; AudioFormat audioFormat = Microphones.getSelectedFormat().getAudioFormat(); Util.log(contact, "Recorder: start."); Util.log(contact, "Recorder: target audio format: " + audioFormat); // DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, // audioFormat); // throws LineUnavailableException // line = (TargetDataLine) AudioSystem.getLine(dataLineInfo); Microphone microphone = Microphones.getCurrentMicrophone(); Util.log(contact, "Recorder: microphone: " + microphone); line = (TargetDataLine) microphone.getLine(); line.open(audioFormat, Config.BUFFER_SIZE_CALLS.getIntegerValue()); line.start(); } @Override public void run() { CallFactory.openCall(contact); byte buffer[] = new byte[Config.BUFFER_SIZE_CALLS.getIntegerValue()]; bytesSent = 0; final long startTime = System.currentTimeMillis(); Thread statsThread = new Thread(new Runnable() { @Override public void run() { while (isCallOpen()) { long now = System.currentTimeMillis(); long diffTime = now - startTime; if (diffTime > 0) { float speed = bytesSent / diffTime * 1000; CallUi.updateCallStats(contact, -1, -1, speed, bytesSent); Util.sleep(5_000); } } } }, "CallRecorder -> (Stats)"); statsThread.start(); statsThread.setPriority(Thread.MIN_PRIORITY); Thread.currentThread().setPriority(Thread.MAX_PRIORITY); try { while (isCallOpen() && line.isOpen()) { int cnt = line.read(buffer, 0, buffer.length); if (cnt > 0) { // Save data in output stream object. out.write(buffer, 0, cnt); for (OutputStream out : captureStreams) { out.write(buffer, 0, cnt); } bytesSent += cnt; } } // System.out.println("connected = " + isConnected() + // ", line.isOpen() = " + line.isOpen() + " (2)"); out.flush(); } catch (SocketException e) { Util.log(contact, "Recorder: " + e.getLocalizedMessage()); } catch (Exception e) { e.printStackTrace(); } CallFactory.closeCall(contact); } @Override public void onCallClose() { Util.log(contact, "Recorder: stop."); if (line.isRunning()) line.stop(); if (line.isOpen()) line.close(); CallUi.updateCallStats(contact, -1, -1, 0, 0); super.onCallClose(); } public void saveTo(Capture capture) { OutputStream out = capture.getCaptureOutputStream(); if (out != null) { captureStreams.add(new BufferedOutputStream(out, 256 * 1024)); } } @Override public String getId() { return "CallRecorder<" + contact.getId() + ">"; } }