javaaudioformat

Getting supported AudioFormat list from AudioSystem


I would like to be able to investigate the available AudioFormat types supported on a system with a view to selecting an appropriate one from a range of options, using preferred and fall-back values for frame rate and channels.

AudioSystem doesn't support directly querying supported audio formats, but I can get a list of available SourceDataLine from a Mixer. And SourceDataLine inherits a DataLine.Info internal calls, which has a method to return the available formats: getFormats ().

So my primary question is: Is there a way to get an array of supported AudioFormat objects out of the Java audio system?

Failing that: Is there a way to get an array of supported AudioFormat objects out of a Mixer?

And failing that: Is it possible to get a DataLine.Info object from a SourceDataLine ?

Ideally, I would like to do something like the following:

    public void exec () {
        Mixer.Info [] mixerInfoList = AudioSystem.getMixerInfo ();
        for (Mixer.Info mixerInfo : mixerInfoList) {
            System.out.println (mixerInfo.getDescription ());
            Mixer mixer = AudioSystem.getMixer (mixerInfo);
            Line.Info [] lineInfoList = mixer.getSourceLineInfo ();
            for (Line.Info rawLineInfo : lineInfoList) {
                System.out.println ("  " + rawLineInfo.toString ());
                DataLine.Info lineInfo = (DataLine.Info) rawLineInfo;
                AudioFormat [] formats = lineInfo.getFormats ();
                for (AudioFormat fmt : formats) {
                    System.out.println ("    " + fmt.toString ());
                }
            }
        }
    }

But this fails on the line DataLine.Info lineInfo = (DataLine.Info) rawLineInfo; because rawLineInfo is obviously an implementation-dependent object, not an instance of DataLineInfo.

It really is tremendously disappointing that mixer.getSourceLineInfo () doesn't return an array of DataLine.Info. There's no reason why it couldn't as the lines concerned are known with certainty to be implementations of SourceDataLine and therefore must support an AudioFormat.

Using the information provided by @gpasch (thanks heaps buddy) in the accepted answer, here's my final solution. Function isDesirable identifies only audio formats I'm interested in. Class AudioFormatKey is a wrapper that provides implementations of equals() for the distinct() transform, and compareTo() for the sorted() transform.

    public void exec () {
        System.out.println ("Available formats (stream):");
        Arrays.stream (AudioSystem.getSourceLineInfo (new Line.Info (SourceDataLine.class)))
                .filter (info -> info instanceof DataLine.Info)
                .map (info -> (DataLine.Info) info)
                .flatMap (dlinfo -> Arrays.stream (dlinfo.getFormats ()))
                .filter (this::isDesirable)
                .map (AudioFormatKey::new)
                .distinct ()
                .sorted ()
                .map (AudioFormatKey::getFormat)
                .forEach (format -> System.out.println ("  " + format));
    }

Solution

  • I have this thing - it gets a list of formats in Windows. I don't know if all are supported or they work but it gives a list.

      public void getFormats() {
        Line.Info desired = new Line.Info( SourceDataLine.class );
        Line.Info[] info = AudioSystem.getSourceLineInfo( desired );
        for ( int i = 0;  i < info.length; ++i ) {
          System.out.println(i+" "+info[i].toString());
          if ( info[ i ] instanceof DataLine.Info ) {
            AudioFormat[] forms = ((DataLine.Info) info[i]).getFormats();
            for ( int n = 0;  n < forms.length;  ++n ) System.out.println( forms[ n ].toString() );
          }
        }
        desired = new Line.Info( TargetDataLine.class );
        info = AudioSystem.getTargetLineInfo( desired );
        for ( int i = 0;  i < info.length; ++i ) {
          System.out.println(i+" "+info[i].toString());
          if ( info[ i ] instanceof DataLine.Info ) {
            AudioFormat[] forms = ((DataLine.Info) info[i]).getFormats();
            for ( int n = 0;  n < forms.length;  ++n ) System.out.println( forms[ n ].toString() );
          }
        }
      }