Control Pulseaudio from Shell

As you know I mainly use Fluxbox on a minimal Ubuntu installation without access to all the every-day functionality provided by panel applets in Gnome, including volume control. Therefore, I have been using pavucontrol for controlling Pulseaudio. It is a really nice application that gives you very finegrained control, for instance over which application should be how loud. Lately I have been annoyed with opening a whole application just for the sake of adjusting volume a little bit, so I set out to find a way to control it via shell. Turns out there is no convenient interface to pulseaudio at all, leaving me to script something together, this time in Ruby. It uses a very unwieldy interface to Pulseaudio named pacmd, contained in Ubuntu package pulseaudio-utils.

def current
  c = IO::popen("pacmd \"list-sinks\" | grep volume | head -1").readlines[0]
  return c.split(" ").last.sub("%", "").strip.to_i

def max
  c = IO::popen("pacmd \"list-sinks\" | grep \"volume steps\" | head -1").readlines[0]
  return c.split(" ").last.strip.to_i - 1

def index
  c = IO::popen("pacmd \"list-sinks\" | grep index | head -1").readlines[0]
  return c.split(" ").last.strip.to_i

def set(v)
  IO::popen("pacmd \"set-sink-volume #{index} #{v}\"").readlines

def muted
  c = IO::popen("pacmd \"list-sinks\" | grep muted | head -1").readlines[0]
  return c.split(" ").last.strip == "yes"

def toggle
  t = 1
  if ( muted )
    t = 0
  IO::popen("pacmd \"set-sink-mute #{index} #{t}\"").readlines

interval = 5

if ( ARGV.size == 0 )
  puts current
elsif (ARGV[0] == "?" )
  puts muted
elsif ( ARGV[0] == "+" )
  set([current + interval, 100].min * (max / 100.0).round)
elsif ( ARGV[0] == "-" )
  set([current - interval, 0].max * (max / 100.0).round)
elsif ( ARGV[0] == "!" )

This is certainly not the most efficient way to do it, retrieving all the info multiple times, but it works and I do not perceive any delays. Note that the script will just use the first sink that pacmd prints, so if you have a setup with multiple sinks you will have to be more clever.

Of course, the obligatory Fluxbox key bindings

None XF86AudioLowerVolume :execCommand pavol -
None XF86AudioRaiseVolume :execCommand pavol +
None XF86AudioMute :execCommand pavol !

and conky volume display:

Vol: ${exec if [ `pavol ?` != 'true' ]; then echo `pavol`%; else echo 'Muted'; fi}

Update: The script now has a home on GitHub.


  1. By changing line 41 to

    set((current + interval) * (max / 100.0).round)

    you can actually turn volume up beyond 100%. That, according to documentation, introduces clipping, but might be the only way to listen to very faint sound sources.

  2. Regolare volume Pulseaudio « Bao Blog Notes - pingback on September 19th, 2011 at 11:31
  3. [Solved] i3wm, Pop-ups - pingback on October 9th, 2011 at 00:19

Trackbacks and Pingbacks: