I've been reading up on the Java Sound API for the last few weeks and I still can't figure out if this is possible. I ask because I want to write a program that takes sound data passing through the system headed for an output line, like my computer's speakers or headphone jack, and writes that data to an audio file.
From what I have read so far about javax.sound.sampled
, it seems like I can only read in data from a Mixer
via a TargetDataLine
; however, after writing a test program (provided below) to query my system for available mixers and then query those mixers for available target and source data lines; I realized all my output mixers except for my default mixer only supported SourceDataLine
s. Furthermore, I can't tell whether the TargetDataLine
from my computer's default mixer (I have a Macbook pro), can read audio data sent to the mixer from other applications. So before I delve further into this project, I want to figure out if it's even possible to access sound being sent through mixers by other applications.
Test Program
import javax.sound.sampled.*;
import java.util.Scanner;
public class Capture {
public static final String ANSI_RED = "\u001B[31m";
public static final String ANSI_GREEN = "\u001B[32m";
public static final String ANSI_RESET = "\u001B[m";
private Mixer mixer;
public Capture() {
Mixer.Info[] installedMixers = AudioSystem.getMixerInfo();
for(int n = 0; n < installedMixers.length; n++) {
System.out.println(ANSI_GREEN + "[" + n + "] " + ANSI_RESET + installedMixers[n].toString());
}
while(mixer == null) {
int choice;
try {
System.out.print("Choose a mixer: ");
Scanner s = new Scanner(System.in);
choice = s.nextInt();
if(choice >= 0 && choice < installedMixers.length)
mixer = AudioSystem.getMixer(installedMixers[choice]);
else
System.out.println(ANSI_RED + "Invalid Choice!" + ANSI_RESET);
} catch(RuntimeException e) {
System.out.println(ANSI_RED + "Please input an integer corresponding to your mixer choice." + ANSI_RESET);
}
}
System.out.println(ANSI_RED + "Source Lines:" + ANSI_RESET);
Line.Info[] sourceLines = mixer.getSourceLineInfo();
if(sourceLines.length == 0) {
System.out.println("None");
}
for(int n = 0; n < sourceLines.length; n++) {
System.out.println(ANSI_GREEN + "[" + n + "] " + ANSI_RESET + sourceLines[n].toString());
}
System.out.println(ANSI_RED + "Target Lines:" + ANSI_RESET);
Line.Info[] targetLines = mixer.getTargetLineInfo();
if(targetLines.length == 0) {
System.out.println("None");
}
for(int n = 0; n < targetLines.length; n++) {
System.out.println(ANSI_GREEN + "[" + n + "] " + ANSI_RESET + targetLines[n].toString());
}
}
public static void main(String[] args) {
Capture recording = new Capture();
}
}
P.S. I found a 2 other questions related to this exact topic that didn't seem to provide solutions at all. One was never answered, the other had a solution that didn't work for the asker, and that I couldn't reproduce.