4

I am running a signed applet that needs to provide the ability for the user to select the input and output audio devices ( similar to what skype provides).

I borrowed the following code from other thread:

import javax.sound.sampled.*;
public class SoundAudit {
  public static void main(String[] args) { try {
    System.out.println("OS: "+System.getProperty("os.name")+" "+
      System.getProperty("os.version")+"/"+
      System.getProperty("os.arch")+"\nJava: "+
      System.getProperty("java.version")+" ("+
      System.getProperty("java.vendor")+")\n");
      for (Mixer.Info thisMixerInfo : AudioSystem.getMixerInfo()) {
        System.out.println("Mixer: "+thisMixerInfo.getDescription()+
          " ["+thisMixerInfo.getName()+"]");
        Mixer thisMixer = AudioSystem.getMixer(thisMixerInfo);
        for (Line.Info thisLineInfo:thisMixer.getSourceLineInfo()) {
            if (thisLineInfo.getLineClass().getName().equals(
              "javax.sound.sampled.Port")) {
              Line thisLine = thisMixer.getLine(thisLineInfo);
              thisLine.open();
              System.out.println("  Source Port: "
                +thisLineInfo.toString());
              for (Control thisControl : thisLine.getControls()) {
                System.out.println(AnalyzeControl(thisControl));}
              thisLine.close();}}
        for (Line.Info thisLineInfo:thisMixer.getTargetLineInfo()) {
          if (thisLineInfo.getLineClass().getName().equals(
            "javax.sound.sampled.Port")) {
            Line thisLine = thisMixer.getLine(thisLineInfo);
            thisLine.open();
            System.out.println("  Target Port: "
              +thisLineInfo.toString());
            for (Control thisControl : thisLine.getControls()) {
              System.out.println(AnalyzeControl(thisControl));}
            thisLine.close();}}}
  } catch (Exception e) {e.printStackTrace();}}
  public static String AnalyzeControl(Control thisControl) {
    String type = thisControl.getType().toString();
    if (thisControl instanceof BooleanControl) {
      return "    Control: "+type+" (boolean)"; }
    if (thisControl instanceof CompoundControl) {
      System.out.println("    Control: "+type+
        " (compound - values below)");
      String toReturn = "";
      for (Control children:
        ((CompoundControl)thisControl).getMemberControls()) {
        toReturn+="  "+AnalyzeControl(children)+"\n";}
      return toReturn.substring(0, toReturn.length()-1);}
    if (thisControl instanceof EnumControl) {
      return "    Control:"+type+" (enum: "+thisControl.toString()+")";}
    if (thisControl instanceof FloatControl) {
      return "    Control: "+type+" (float: from "+
        ((FloatControl) thisControl).getMinimum()+" to "+
        ((FloatControl) thisControl).getMaximum()+")";}
    return "    Control: unknown type";}
}

But what I get:

Mixer: Software mixer and synthesizer [Java Sound Audio Engine]
Mixer: No details available [Microphone (Pink Front)]

I was expecting the get the real list of my devices (My preferences panels shows 3 output devices and 1 Microphone). I am running on Mac OS X 10.6.7.

Is there other way to get that info from Java?

Community
  • 1
  • 1
Johnny Everson
  • 8,343
  • 7
  • 39
  • 75

3 Answers3

4

For years it has been a very unfortunate limitation of the Java implementation for OS X, being BTW particular for that platform, that "Java Sound Audio Engine" is the only programmatically available output audio line. In consequence, whatever you send to this line, i.e. out from any java application that you make, will always be routed to what has been set as the default output in the OS X, typically internal speakers. So the JSAE is just Java terminology for "default audio out". To our understanding - sadly - this is still the case with latest release.

Why unfortunate ? Because it effectively disables even humble audio routing. We are working with these matters on a daily basis, and it calls for all sorts of added complexity. There are work arounds, but via third party apps as SoundFlower and HiJack Pro. www.soundPimp.com for example.

carl
  • 501
  • 3
  • 10
3

Maybe you can modify and use this. The following code is used to select audio output devices on two of my Applets. I was only interested in output lines, not ports or input lines. The first part lists the options in an option group in a Menubar dropdown. The second part sets a mixer variable based upon the selected option.

private void createMenuBars(){
    JMenuBar menuBar = new JMenuBar();
    menuBar.setBounds(0, 0, 60, 20);

    JMenu optionMenu = new JMenu("Options");
    JMenuItem pickMixers = new JMenuItem("Select a Playback Path");
    optionMenu.add(pickMixers);
    optionMenu.addSeparator();

    ButtonGroup mixerSelections = new ButtonGroup();

    addMixerOption("default sound system", mixerSelections, optionMenu, true);

    AudioFormat audioFmt = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 
        44100, 16, 2, 4, 44100, false);
    Mixer.Info[] mixers = AudioSystem.getMixerInfo();
    for (Mixer.Info info : mixers) 
    {
        Mixer mixer = AudioSystem.getMixer(info);

        try
        {
//          System.out.println(info);
            Info sdlLineInfo = new DataLine.Info(SourceDataLine.class, audioFmt);

            // test if line is assignable
            @SuppressWarnings("unused")
            SourceDataLine sdl = (SourceDataLine) mixer.getLine(sdlLineInfo);

            // if successful, add to list
            addMixerOption(info.getName() + " <> " + info.getDescription(),
                mixerSelections, optionMenu, false);
        }
        catch (LineUnavailableException e) 
        {
            //e.printStackTrace();
            System.out.println("Mixer rejected, Line Unavailable: " + info);
        }
        catch (IllegalArgumentException e)
        {
            //e.printStackTrace();
            System.out.println("Mixer rejected, Illegal Argument: " + info);
        }           
    }

    menuBar.add(optionMenu);
    add(menuBar,0);
}

private void addMixerOption(String optionName, ButtonGroup bg, 
    JMenu menu, boolean isSelected
{
    JRadioButtonMenuItem newOption = new JRadioButtonMenuItem(optionName);
    bg.add(newOption);
    newOption.setSelected(isSelected);
    menu.add(newOption);
    newOption.addActionListener(new OptionListener());
    newOption.setActionCommand(optionName); 
}

Here is were the mixer variable gets set when an option is selected.

public class OptionListener implements ActionListener 
{
    @Override
    public void actionPerformed(ActionEvent arg0) 
    {
        String optionName = arg0.getActionCommand();
        Boolean defaultMixer = true;

        Mixer.Info[] mixers = AudioSystem.getMixerInfo();
        for (Mixer.Info info : mixers)
        {
            if (optionName.equals(info.getName()+" <> "+info.getDescription()))
            {
                System.out.println("Option selected >  " + info.getName());
                System.out.println("    description >  " + info.getDescription());
                System.out.println("          class >  " + info.getClass());

                appMixer = AudioSystem.getMixer(info);
                System.out.println(appMixer);
                defaultMixer = false;
            }
        }
        if (defaultMixer) 
        {
            System.out.println("Using default mixer, whatever that is...");
            appMixer = null;
        }
    }
}

There's an overabundance of console messages. I use this in http://hexara.com/VSL/JTheremin.htm

Phil Freihofner
  • 7,645
  • 1
  • 20
  • 41
  • Phil, thank you but your code does the same as mine ( in terms of which devices are listed). I have 3 output devices on my Mac and yet, the java sound api only lists: "Java Sound Audio Engine". That was the only option in preferences on your applet too. – Johnny Everson Nov 13 '11 at 11:45
  • @Jhonny - Sorry to hear this wasn't more helpful. Did you look at both the choices put into the Option selection and the ones "rejected" and listed on the console? Still not finding things? Drag. – Phil Freihofner Nov 13 '11 at 21:47
  • yes, I got: Mixer rejected, Illegal Argument: Microphone (Pink Rear), version Unknown Version. But none of the output devices where listed. – Johnny Everson Nov 14 '11 at 01:00
1

This might be either that the JVM does not support retrieving this information on OS X or your devices might not be supported. I would do two things:

  • try with different JVM
  • try on different OS

I run the code on linux and I got all the details correctly :

OS: Linux 2.6.38-12-generic/amd64
Java: 1.6.0_22 (Sun Microsystems Inc.)

Mixer: the ear-candy mixer [PulseAudio Mixer]
Mixer: Direct Audio Device: default, default, default [default [default]]
Mixer: Direct Audio Device: HDA Intel, ALC662 rev1 Analog, ALC662 rev1 Analog [Intel [plughw:0,0]]
Mixer: Direct Audio Device: Plantronics Headset, USB Audio, USB Audio [Headset [plughw:1,0]]
Mixer: Direct Audio Device: USB Device 0x46d:0x8b2, USB Audio, USB Audio [U0x46d0x8b2 [plughw:2,0]]
Mixer: HDA Intel, Realtek ALC662 rev1 [Port Intel [hw:0]]
  Source Port: Mic Boost source port
    Control: Mic Boost (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Balance (float: from -1.0 to 1.0)
  Source Port: Capture source port
    Control: Capture (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Balance (float: from -1.0 to 1.0)
      Control: Select (boolean)
  Source Port: Capture source port
    Control: Capture (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Balance (float: from -1.0 to 1.0)
      Control: Select (boolean)
  Target Port: Master target port
    Control: Master (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Mute (boolean)
  Target Port: Headphone target port
    Control: Headphone (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Balance (float: from -1.0 to 1.0)
      Control: Mute (boolean)
  Target Port: Speaker target port
    Control: Speaker (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Balance (float: from -1.0 to 1.0)
      Control: Mute (boolean)
  Target Port: PCM target port
    Control: PCM (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Balance (float: from -1.0 to 1.0)
      Control: Mute (boolean)
  Target Port: Line target port
    Control: Line (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Balance (float: from -1.0 to 1.0)
      Control: Mute (boolean)
  Target Port: Mic target port
    Control: Mic (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Balance (float: from -1.0 to 1.0)
      Control: Mute (boolean)
  Target Port: Mic Boost target port
    Control: Mic Boost (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Balance (float: from -1.0 to 1.0)
Mixer: Plantronics Headset, USB Mixer [Port Headset [hw:1]]
  Source Port: Bass source port
    Control: Bass (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
  Source Port: Treble source port
    Control: Treble (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
  Source Port: Mic source port
    Control: Mic (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Select (boolean)
  Target Port: Bass target port
    Control: Bass (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
  Target Port: Treble target port
    Control: Treble (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
  Target Port: PCM target port
    Control: PCM (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Balance (float: from -1.0 to 1.0)
      Control: Mute (boolean)
Mixer: USB Device 0x46d:0x8b2, USB Mixer [Port U0x46d0x8b2 [hw:2]]
  Source Port: Mic source port
    Control: Mic (compound - values below)
      Control: Volume (float: from 0.0 to 1.0)
      Control: Select (boolean)
Peter Szanto
  • 7,568
  • 2
  • 51
  • 53
  • 1
    yes, this problem only happens on Mac Os. They is basically if there is an api/native api that works on Mac and Win. – Johnny Everson Nov 14 '11 at 11:06
  • Are you using the latest Oracle JVM? If that doesnt work then it must be serious reason why Oracle couldn't implement it. Anyways there is a desciption how to access hardware on mac with native code : http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Intro/AH_Intro.html – Peter Szanto Nov 14 '11 at 11:46
  • 1
    I'm using the default that comes with Mac OS X. I cannot ask the users to upgrade their JVM. – Johnny Everson Nov 14 '11 at 15:02
  • In this case I would suggest two things : 1:) download the OSX sourcecode of the JVM and and see if there is any extra platform specific parameter that you could pass in to get more results. 2)If that wont work and you cannot ask users to change their machines then you need to find a native OS X application that is by default installed on all machines and returns you this information. From this step this is not really a stacoverflow question, ask it rather at http://apple.stackexchange.com/ – Peter Szanto Nov 14 '11 at 15:09