1

I'm working on a project that will change the brightness of keyboard lights with PWM signal, according to output sound levels. That trouble is, I need the output stream in real time. So far I used javax.sound.sampled package and I never succeeded grabbing the audio output. However, what have I done was to use targetDataLine and sourceDataLine, which don't look like the way to go, I'm still trying though. What I need is an audio stream provider, which my java app can "hear" and process it. So far, I viewed many tutorials, videos, posts, some articles (like this one: https://cr.openjdk.java.net/~iris/se/12/latestSpec/api/java.desktop/javax/sound/sampled/class-use/Mixer.Info.html ) etc. but no results. Has somebody done it before ? Or is out there a library other than sampled library ? Any help would be appreciated.

The error I get for every single format:

java.lang.IllegalArgumentException: Line unsupported: interface TargetDataLine supporting format PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian
    at com.sun.media.sound.DirectAudioDevice.getLine(Unknown Source)
    at javax.sound.sampled.AudioSystem.getTargetDataLine(Unknown Source)

The code used:

package audio;
import javax.sound.sampled.*;

public class App1 {
    public static String getWord(String arr) {
        int i = 0;
        for(; i < arr.length(); i++) {
            if (arr.charAt(i) == ' ')
                break;
        }
        return arr.substring(0,i);
    }

    public static void wait(int ms) {
        try{
            Thread.sleep(ms);
        }
        catch(InterruptedException ex){
            Thread.currentThread().interrupt();
        }
    }

    public static AudioFormat getAudioFormat(){
        float sampleRate = 44100;
        //8000,11025,16000,22050,44100
        int sampleSizeInBits = 16;
        //8,16
        int channels = 1;
        //1,2
        boolean signed = true;
        //true,false
        boolean bigEndian = false;
        //true,false
        //return new AudioFormat(Encoding.PCM_SIGNED, sampleRate, 16, 1, 2, sampleRate, false);
        return new AudioFormat(sampleRate,
                               sampleSizeInBits,
                               channels,
                               signed,
                               bigEndian);
    }

    public static void main(String [] args) {
        try {
            //-----DECLARATIONS-----
            TargetDataLine targetDataLine = null;
            Mixer.Info[] mixers = AudioSystem.getMixerInfo();
            Mixer.Info m = null;
            String expectedMixer = "Speakers";      

            //-----MIXER FINDER-----
            System.out.println("Number of mixers: " + mixers.length);
            for(int i = 0; i < mixers.length; i++) {
                System.out.println(getWord(mixers[i].getName()));
                if(getWord(mixers[i].getName()).compareTo(expectedMixer) == 0){
                    m = mixers[i];
                }
            }
            if(m==null) throw new Exception("No such mixer found: " + expectedMixer);
            else System.out.println('\n'+"Device choosen: "+m.getName());

            //-----LINE TESTER-----
            boolean v = false, showError = true; // show error or keep trying several times
            int tries = 3, i = 0;
            while(v==false && i++ < tries){
                try {
                    //sourceDataLine = AudioSystem.getTargetDataLine(getAudioFormat(), m);
                    targetDataLine = AudioSystem.getTargetDataLine(getAudioFormat(), m);
                    targetDataLine.open(getAudioFormat());
                    v=true;
                    //System.out.println("Success!");
                } catch (IllegalArgumentException e){
                    if (showError) {
                        v = true;
                        e.printStackTrace();
                    }
                    else {
                        System.out.println("Error! Retrying...  "+i+'/'+tries);
                        v = false;
                    }
                    wait(2000);
                }
            }
            if(i-1==tries)
                //System.out.println("No success :(");
                throw new Exception("No success :(");
            else
                if(v==false)
                    System.out.println("SourceData line found and accepted !");

            //-----SIGNAL PROCESSING-----
            //nothing here because the rest isn't working

        } catch(Exception e) { e.printStackTrace();} 
    }
}

Lately, I've been searching for some piece of code to discover available formats, and I've made something between my code and edoloughlin's code:

package audio;
import javax.sound.sampled.*;

public class App2 {
    public static String getWord(String arr) {
        int i = 0;
        for(; i < arr.length(); i++) {
            if (arr.charAt(i) == ' ')
                break;
        }
        return arr.substring(0,i);
    }

    public static void wait(int ms) {
        try{
            Thread.sleep(ms);
        }
        catch(InterruptedException ex){
            Thread.currentThread().interrupt();
        }
    }

    public static AudioFormat getAudioFormat(){
        float sampleRate = 44100;
        //8000,11025,16000,22050,44100
        int sampleSizeInBits = 16;
        //8,16
        int channels = 1;
        //1,2
        boolean signed = true;
        //true,false
        boolean bigEndian = false;
        //true,false
        //return new AudioFormat(Encoding.PCM_SIGNED, sampleRate, 16, 1, 2, sampleRate, false);
        return new AudioFormat(sampleRate,
                               sampleSizeInBits,
                               channels,
                               signed,
                               bigEndian);
    }

    public static void main(String [] args) {
        try {
            String expectedMixer = "Speakers";
            Mixer.Info[] mixers = AudioSystem.getMixerInfo();
            Mixer.Info m = null;
            for(int i = 0; i < mixers.length; i++) {
                if(getWord(mixers[i].getName()).compareTo(expectedMixer) == 0){
                    m = mixers[i];
                }
            }

            int sampleRates[] = { 8000, 11025, 16000, 22050, 44100 };
            int channels[] = { 1, 2 };
            int bytesPerSample[] = { 1, 2 };
            boolean signature[] = {true, false};

            AudioFormat format;
            DataLine.Info lineInfo;


           //for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) {
                for (int a = 0; a < sampleRates.length; a++) {
                    for (int b = 0; b < channels.length; b++) {
                        for (int c = 0; c < bytesPerSample.length; c++) {
                            for(int d = 0; d < signature.length; d++) {
                                format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                                        (float)sampleRates[a], 8 * bytesPerSample[c], channels[b], bytesPerSample[c],
                                        (float)sampleRates[a], signature[d]);
                                lineInfo = new DataLine.Info(/*dataLineClass*/TargetDataLine.class, format);
                                if (AudioSystem.isLineSupported(lineInfo)) {
                                    /*
                                     * TODO: To perform an exhaustive search on supported lines, we should open
                                     * TODO: each Mixer and get the supported lines. Do this if this approach
                                     * TODO: doesn't give decent results. For the moment, we just work with whatever
                                     * TODO: the unopened mixers tell us.
                                     */
                                    if (AudioSystem.getMixer(/*mixerInfo*/m).isLineSupported(lineInfo)) {
                                        //formats.add(format);
                                        System.out.println(format);
                                    }
                                }
                            }
                        }
                    }
                }
           //}
        }catch(Exception e) {e.printStackTrace();}
    }
}

As shown above, I used many format combinations, but nothing gets printed out in the console. I wonder if my system/java app supports such a task. If not, is there a way to achieve the goal ? (read real-time output)

Alex
  • 21
  • 3
  • It is probably worthwhile tidying up this question to clear up some ambiguities. If you are looking to grab system audio, the wav a look at this SO question: [Recording System Audio via Java](https://stackoverflow.com/a/34679422/8876321) – fdcpp Jan 26 '20 at 11:36
  • If the audio is coming from your Java application, then one of the following may be more inuitive: [Java Sound API: Java Sound Demo](http://java.sun.com/products/java-media/sound/&usg=AOvVaw2A91BNWID4SoSuNPX_Qriv), [TarsosDSP](https://github.com/JorenSix/TarsosDSP), [Minim](https://github.com/ddf/Minim) – fdcpp Jan 26 '20 at 11:38
  • Well, I'm looking forward to get real-time output, like music, coming from chrome, youtube music, system sounds, players, whatever. What I get is microphone line, which I **do not** need. Also, I've searched for hacky methods to make speakers default input device, but no success. The first link you presented may be helpful, but I don't understand: `connect your application to the main sound driver`. Btw, the application is not meant to output any sound. Anyway, thank you for your help – Alex Jan 26 '20 at 12:14
  • _connect your application to the main sound driver_ is referring to what inputs/outputs exist. As referenced in the answer, look at `static Mixer.Info[] getMixerInfo()` – fdcpp Jan 26 '20 at 12:40
  • I have some updates ! I did what you recommended to me. It kinda works, but i get IllegalArgumentException every time. As I've read on the Internet, the problem seems to be coming from unaccepted format.(I'm using PCM_SIGNED 16000.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian). Whatever I tried, I always have been given this error. What can I do now ? – Alex Jan 26 '20 at 15:00
  • Can you confirm that the sample rate you have used is a factor? Have you tried 44.1kHz, or whatever your system audio sample rate is? – fdcpp Jan 26 '20 at 16:43
  • I guess so. In fact, any method for target or source data lines require the audio format that involves sample rate. I tried with 44.1kHz and also my system's format (16 bits, 48kHz) as well – Alex Jan 26 '20 at 17:15
  • What error are you getting exactly? – fdcpp Jan 26 '20 at 19:05
  • This is the error: `java.lang.IllegalArgumentException: Line unsupported: interface TargetDataLine supporting format PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian at com.sun.media.sound.DirectAudioDevice.getLine(Unknown Source) at javax.sound.sampled.AudioSystem.getTargetDataLine(Unknown Source) at audio.App.main(App.java:64)` and it is coming from this line: `targetDataLine = AudioSystem.getTargetDataLine(getAudioFormat(), m);`. Any ideas ? – Alex Jan 27 '20 at 15:55
  • Put that error in your question and [start here](https://stackoverflow.com/questions/6002444/java-recording-from-mixer?r=SearchResults) – fdcpp Jan 27 '20 at 16:25
  • Hello! The post you pointer to does not help much.. and btw i have updated my thread – Alex Jan 31 '20 at 06:06
  • [and here?](https://stackoverflow.com/a/12484623/8876321) – fdcpp Jan 31 '20 at 06:12
  • Also, haver you inspected what is returned from `getMixerInfo()`? how many mixers and any identifying features? – fdcpp Jan 31 '20 at 07:59
  • I printed out `getMixerInfo()` and this is what i got: [Ljavax.sound.sampled.Mixer$Info;@59fa1d9b. About mixers. This is what I got: `Primary Sound Driver Speakers (4- High Definition Audio Device) Port Speakers (4- High Definition Au` – Alex Jan 31 '20 at 12:26
  • Hi again! I was thinking: what if, instead of using sampled library, use [JNA](https://java-native-access.github.io/jna/4.2.1/com/sun/jna/Native.html), or some java native audio library. Is it possible to reach the target ? – Alex Feb 21 '20 at 18:03

0 Answers0