Systems Performance 2nd Ed.

BPF Performance Tools book

Recent posts:
Blog index

Audio Volume CLI

05 Mar 2007

I originally posted this at

While Solaris has a fancy GNOME based desktop called JDS3, other desktop environments are available and work fine. FVWM2 is a fast alternative with a modest set of features, and is available on the Software Companion CD (which you may already have a copy of).

If you have installed fvwm2 from the companion CD and would like to try it, the easiest way is to enter a fail safe session from the login screen, then run the binary: /opt/sfw/bin/fvwm2. The proper way is to create config files under /etc/dt/config, so that the login screen provides FVWM as an option.

After getting fvwm2 running, I found my volume up/down/mute keys on this Sun type 7 keyboard didn't work. An Internet search didn't find any solutions. To get these keys to work, I wrote a short C program to ioctl /dev/audioctl, and added some lines to the .fvwmrc file. I'm writing this quick blog entry to help the next person doing the same Internet search. If there is a better way to do this in Solaris already (like a shipped binary), I missed it!

This is my C program:

/* volumeset.c - set Sun's /dev/audio play volume */


usage(char *name)
        (void) printf("USAGE: %s [+|-]volume_percent\n", name);
        (void) printf("   eg,\n");
        (void) printf("       %s 100     # maximum volume\n", name);
        (void) printf("       %s +5      # plus 5 percent\n", name);

main(int argc, char *argv[])
        audio_info_t ai;
        int fd, vol, mod, gain;

        if (argc < 2)

        switch (argv[1][0]) {
                case '+':
                        mod = 1;
                        vol = atoi(&argv[1][1]);
                case '-':
                        mod = -1;
                        vol = atoi(&argv[1][1]);
                case '0'...'9':
                        mod = 0;
                        vol = atoi(argv[1]);
                        if (vol > 100 || vol < 0) {
                                (void) printf("ERROR: volume must be "
                                    "between 0 and 100.\n");

        if (mod != 0 && vol == 0)

        if ((fd = open("/dev/audioctl", O_RDONLY)) == -1) {
                (void) perror("can't open /dev/audioctl");

        if (ioctl(fd, AUDIO_GETINFO, &ai) == -1) {
                (void) perror("fetching audio state failed");

        if (mod == 0)
                gain = (vol * 255) / 100;
                gain = + (mod * vol * 255) / 100;
        if (gain < 0)
                gain = 0;
        if (gain > 255)
                gain = 255; = gain;
        ai.output_muted = gain == 0 ? 1 : 0;

        if (ioctl(fd, AUDIO_SETINFO, &ai) == -1) {
                (void) perror("setting audio state failed");

        (void) close(fd);

        return (0);

If you don't have Sun's C compiler installed, you can compile it using /usr/sfw/bin/gcc -o volumeset volumeset.c.

The following are the lines I added to ~/.fvwm/.fvwm2rc to bind the audio keys on the top left to the volumeset program (copied to /usr/local/bin). These bindings probably work for type 6 keyboards as well (haven't tried):

Key SunAudioMute A       A       Exec /usr/local/bin/volumeset 0
Key SunAudioLowerVolume A A      Exec /usr/local/bin/volumeset -15
Key SunAudioRaiseVolume A A      Exec /usr/local/bin/volumeset +15

The above lines bind the keys to mute the volume, decrease by 15% or increase by 15% (it may be better to make the mute behave as a toggle, rather than always mute). After restarting fvwm, my audio keys now work fine.