Can Java Sound be used to control the system volume?

25,103

Solution 1

No, it cannot. Here is source adapted from an answer to Adjusting master volume on coderanch. The source iterates the available lines, checks if they have a control of the right type, and if so, puts them in a GUI attached to a JSlider

import java.awt.*;
import javax.swing.*;
import javax.sound.sampled.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class SoundMixer {

    public Component getGui() {
        JPanel gui = new JPanel(new GridLayout(0,1));

        Mixer.Info[] mixers = AudioSystem.getMixerInfo();
        System.out.println(
                "There are " + mixers.length + " mixer info objects");
        for (Mixer.Info mixerInfo : mixers) {
            System.out.println("mixer name: " + mixerInfo.getName());
            Mixer mixer = AudioSystem.getMixer(mixerInfo);
            Line.Info[] lineInfos = mixer.getSourceLineInfo();
            for (Line.Info lineInfo : lineInfos) {
                System.out.println("  Line.Info: " + lineInfo);
                try {
                    Line line = mixer.getLine(lineInfo);
                    FloatControl volCtrl = (FloatControl)line.getControl(
                            FloatControl.Type.MASTER_GAIN);
                    VolumeSlider vs = new VolumeSlider(volCtrl);
                    gui.add( new JLabel(volCtrl.toString()) );
                    gui.add( vs.getVolume() );
                    System.out.println(
                            "    volCtrl.getValue() = " + volCtrl.getValue());
                } catch (LineUnavailableException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException iaEx) {
                    System.out.println("    " + iaEx);
                }
            }
        }

        return gui;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                SoundMixer sm = new SoundMixer();
                Component c = sm.getGui();
                JOptionPane.showMessageDialog(null, c);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
        SwingUtilities.invokeLater(r);
    }
}

class VolumeSlider {

    JSlider volume;

    VolumeSlider(final FloatControl volumeControl) {
        volume = new JSlider(
                (int) volumeControl.getMinimum() * 100,
                (int) volumeControl.getMaximum() * 100,
                (int) volumeControl.getValue() * 100);
        ChangeListener listener = new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                float val = volume.getValue() / 100f;
                volumeControl.setValue(val);
                System.out.println(
                        "Setting volume of " + volumeControl.toString() + 
                        " to " + val);
            }
        };
        volume.addChangeListener(listener);
    }

    public JSlider getVolume() {
        return volume;
    }
}

On this Windows 7 machine I get two controls, both from the "Java Sound Audio Engine". Neither has any effect on the current system volume.

run:
There are 4 mixer info objects
mixer name: Primary Sound Driver
  Line.Info: interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes
    java.lang.IllegalArgumentException: Unsupported control type: Master Gain
  Line.Info: interface Clip supporting 8 audio formats, and buffers of at least 32 bytes
    java.lang.IllegalArgumentException: Unsupported control type: Master Gain
mixer name: Speakers (VIA High Definition Audio)
  Line.Info: interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes
    java.lang.IllegalArgumentException: Unsupported control type: Master Gain
  Line.Info: interface Clip supporting 8 audio formats, and buffers of at least 32 bytes
    java.lang.IllegalArgumentException: Unsupported control type: Master Gain
mixer name: Java Sound Audio Engine
  Line.Info: interface SourceDataLine supporting 8 audio formats
    volCtrl.getValue() = 0.0
  Line.Info: interface Clip supporting 8 audio formats, and buffers of 0 to 4194304 bytes
    volCtrl.getValue() = 0.0
mixer name: Port Speakers (VIA High Definition A
Setting volume of Master Gain with current value: 0.0 dB (range: -80.0 - 13.9794) to 0.0
Setting volume of Master Gain with current value: 0.0 dB (range: -80.0 - 13.9794) to -0.41
Setting volume of Master Gain with current value: 0.0 dB (range: -80.0 - 13.9794) to -0.68
...

Swap FloatControl.Type.MASTER_GAIN for FloatControl.Type.VOLUME to see.. no controls.

Solution 2

add following line just after Line is initialized. this is required to open the line.

boolean opened = line.isOpen() || line instanceof Clip;
if(!opened){
    System.out.println("Line is not open, trying to open it...");
    line.open();
    opened = true;
}

Solution 3

try this it wont disappoint you.... we can modify upper example accordingly.

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;

public class SoundMeter {

JFrame j;

public SoundMeter() {
    j = new JFrame("SoundMeter");
    j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    j.setLayout(new BoxLayout(j.getContentPane(), BoxLayout.Y_AXIS));
    printMixersDetails();
    j.setVisible(true);
}
public void printMixersDetails(){
    javax.sound.sampled.Mixer.Info[] mixers = AudioSystem.getMixerInfo();
    System.out.println("There are " + mixers.length + " mixer info objects");  
    for(int i=0;i<mixers.length;i++){
        Mixer.Info mixerInfo = mixers[i];
        System.out.println("Mixer Name:"+mixerInfo.getName());
        Mixer mixer = AudioSystem.getMixer(mixerInfo);
        Line.Info[] lineinfos = mixer.getTargetLineInfo();
        for(Line.Info lineinfo : lineinfos){
            System.out.println("line:" + lineinfo);
            try {
                Line line = mixer.getLine(lineinfo);
                line.open();
                if(line.isControlSupported(FloatControl.Type.VOLUME)){
                    FloatControl control = (FloatControl) line.getControl(FloatControl.Type.VOLUME);
                    System.out.println("Volume:"+control.getValue());   
                    JProgressBar pb = new JProgressBar();
                    // if you want to set the value for the volume 0.5 will be 50%
                    // 0.0 being 0%
                    // 1.0 being 100%
                    control.setValue((float) 0.5);
                    int value = (int) (control.getValue()*100);
                    pb.setValue(value);
                    j.add(new JLabel(lineinfo.toString()));
                    j.add(pb);
                    j.pack();
                }
            } catch (LineUnavailableException e) {
                e.printStackTrace();
            }
        }
    }
}
public static void main(String[] args) {
    new SoundMeter();
}
}
Share:
25,103
Andrew Thompson
Author by

Andrew Thompson

Java desktop app. enthusiast (for the x-platform, rich client experience). No strong opinions on technologies, platforms etc. beyond that. Author of the SSCCE and wrote the initial draft of the MCVE at SO. Also seen at DrewTubeish. Some of the tools formerly available at my pscode.org domain can be downloaded from my Google Share Drive. At StackExchange: Completed the Java Web Start, JNLP, Applet &amp; Java Sound tag information pages. Top user in same tags. Asked the How to create screenshots? FAQ &amp; wrote the Why CS teachers should stop teaching Java applets blog post. One of the most prolific editors of questions &amp; answers. Most active on StackOverflow but also seen at other places around StackExchange such as Space Exploration, Sci-Fi &amp; Fantasy &amp; Movies &amp; TV.

Updated on July 16, 2022

Comments

  • Andrew Thompson
    Andrew Thompson almost 2 years

    Java Sound offers FloatControl instances for various sound line functionality, and both a MASTER_GAIN & VOLUME control type.

    Can these controls be used to change the system volume?

  • Andrew Thompson
    Andrew Thompson about 11 years
    Nice one. But while that shows two more FloatControl.Type.MASTER_GAIN * lines here, none of them have any affect on system volume. * Still 0 for FloatControl.Type.VOLUME
  • Kislay Sinha
    Kislay Sinha about 11 years
    this code will make system volume to 50% which governed by code :control.setValue((float) 0.5);
  • Torque
    Torque about 11 years
    The above code does not change the master volume on Windows 7.
  • rogerdpack
    rogerdpack almost 11 years
    This does not seem to adjust the master volume for me (win 7)
  • rogerdpack
    rogerdpack almost 11 years
    So what you're saying here is that it's not possible. Is this a JDK bug?
  • Andrew Thompson
    Andrew Thompson almost 11 years
    @rogerdpack The JSE makes no claims to controlling system volume so I imagine, no. But feel free to open a bug report with Oracle and get an answer 'direct from the manufacturer'.
  • Andrew Thompson
    Andrew Thompson over 9 years
    Given it does not use Java Sound, I cannot see how this is an answer to the question asked (which was quite specific about 'using Java Sound').
  • user390525
    user390525 about 8 years
    Does the code changes the whole system sound value or for some specific media app in frames of audio player for example?
  • user390525
    user390525 about 8 years
    I tried the sample on linux jre 1.8.0_60 but it doesn't work; all mixer names have "Unsupported control type: Volume"; Could you give me a tip?
  • Andrew Thompson
    Andrew Thompson about 8 years
    @user390525 "Could you give me a tip?" Be good to your mum.
  • user390525
    user390525 about 8 years
    The platform in the question is not specified, as I can get it; I am using linux so may that be the reason volume control doesn't work?
  • Andrew Thompson
    Andrew Thompson about 8 years
    @user390525 ".. I am using linux so may that be the reason volume control doesn't work?" Yep, looks like. Java Sound on Mac was always patchy, and while an audio 'loop back' was available on Windows, it did not seem to be available on Mac. Not sure with the case on Linux but always noted that Java Sound support was inconsistent across Java implementations (JREs).
  • user390525
    user390525 about 8 years
    @AndrewThompson Ok thanks seems like the issue for linux is much deeper than I expected first :) So the Java Sound API is a bit platform dependent stuff my bad :P But is it always like that in linux or the volume control issue has started since some let say jre/linux version?
  • Andrew Thompson
    Andrew Thompson about 8 years
    @user390525 "But is it always like that in linux or the volume control issue has started since some let say jre/linux version?" Not sure, sorry.