48

I want to read out the volume level I can set with

pactl set-sink-volume $SINK $VOLUME

Is there an easy way to do that? As easy as the hypothetical

pactl get-sink-volume $SINK

?

(What I'm trying to do? I use pactl to set volume and it lets me set the volume higher than 100% which is a bad idea (sound quality goes down), so I'm thinking about writing a small script that will not go over 100%. Read it out. Over some threshold? Set to 100%. Below? add 1%. If there is another way to do that, great, tell me! The cleanest solution would probably to tell pulse to just stop at 100%. But the original question remains, there must be some way..)

I am on Debian if that makes any difference.

As of early 2021, it seems like work is underway to implement this feature in pactl. Thanks to Klaas van Schelven for pointing this out.

It seems there is now (late 2022) a pactl get-sink-volume command.

Higemaru
  • 639
  • 1
  • 6
  • 7
  • `pactl list sinks` gives you the volume, but not in a nice easy format like set-sink-volume. – derobert May 27 '14 at 16:05
  • 2
    There's a question on [Ask Ubuntu](http://askubuntu.com/questions/456842/check-pulseaudio-sink-volume) with an answer giving a nice perl-oneliner to parse the volume out of this. – Andreas Wiese May 27 '14 at 16:23
  • @derobert Thanks, I'll just grep and/or sed it out of there! – Higemaru May 28 '14 at 11:45
  • @AndreasWiese Thanks, didn't see that. I took a quick glance at the perl code but I guess I'll just write my own dirty little script. ;-) – Higemaru May 28 '14 at 11:51
  • @derobert - getting this issue - Connection failure: Connection refused pa_context_connect() failed: Connection refused – inquisitive Feb 18 '21 at 13:18

14 Answers14

32
pactl list sinks | grep '^[[:space:]]Volume:' | \
    head -n $(( $SINK + 1 )) | tail -n 1 | sed -e 's,.* \([0-9][0-9]*\)%.*,\1,'

That's what I have. It's not neat, but it was enough for my use. I couldn't find the way to do it. The pactl just doesn't seem to have any means of getting listing for one sink only, but they are printed in ascending order. So that selects the nth line using tail and head. Notice that the volume line may have separate volumes for right and left channels and that sed substitute only picks the first one, because I needed just that.

For the record, I use the pactl list sinks short to get my active sink number:

pactl list short | grep RUNNING | sed -e 's,^\([0-9][0-9]*\)[^0-9].*,\1,'

EDIT 2017-10-05: I had to tweak those a bit due to changes in pulseaudio. Here's what I have now:

SINK=$( pactl list short sinks | sed -e 's,^\([0-9][0-9]*\)[^0-9].*,\1,' | head -n 1 )
NOW=$( pactl list sinks | grep '^[[:space:]]Volume:' | head -n $(( $SINK + 1 )) | tail -n 1 | sed -e 's,.* \([0-9][0-9]*\)%.*,\1,' )

I have MOD set to +10 or -10 and I make some boundary checks and finally:

pactl set-sink-volume $SINK ${MOD}%
Tommi Kyntola
  • 536
  • 4
  • 5
  • 1
    Thanks! To get active sink number, I needed to use `pactl list sinks short | grep RUNNING | sed -e 's,^\([0-9][0-9]*\)[^0-9].*,\1,'` - Added `sinks` between `pactl list` and `short` – koushik Sep 27 '17 at 06:56
  • 3
    For robustness I would suggest `LC_ALL=C pactl list sinks | grep` because the "Volume:" text may be localized into the user's language. – Marius Gedminas Aug 08 '19 at 19:52
  • 1
    Since I have only one sink, this worked for me in a Bash script: `volume=$(pactl list sinks | grep Volume | head -n1 | awk '{print $5}')` – Matthias Braun Nov 25 '19 at 11:50
  • @MariusGedminas: Alternatively, `pacmd list-sinks` seems to output everything in English, regardless of the user's language. – balu Jan 27 '20 at 18:35
21

If you do not have a restriction to use another program there is the pamixer.

You can get the volume with:

$ pamixer --get-volume
yudi-matsuzake
  • 319
  • 2
  • 2
  • 6
    In Debian, you can use the `pulsemixer` package. It looks about the same. – Josef Kufner Nov 05 '18 at 21:18
  • Unfortunately, this solution has turned out to be quite unreliable for me: The output of `pamixer --get-volume` doesn't match any of the values that `pactl list sinks` shows. Or maybe it's just that I don't understand what units `pamixer` uses? – balu Jan 27 '20 at 18:30
  • @balu It uses percentages by default. – Bogdan M. Jan 09 '21 at 15:45
  • `pamixer` has the same problem of not having a built-in way of using the current running sink. It's just that its default (without specifying `--sink`) is the same as `pactl`'s `@DEFAULT_SINK@`. – OJFord Mar 16 '23 at 16:15
11

Note that Tommi Kyntola's answer relies on the sink to be in use so that you can actually get the sink number.

Also note that it relies on named sink indexes to be the same as the counted index. Let's say, for example, we have 3 sinks 1, 2 and 3 and that 3 is our selected sink, we then disconnect number 2, leaving us with 1 and 3. Now you can't count to sink 3 with Tommi Kyntola's solution because pactl list sinks | grep "^[[:space:]]Volume:" will only output 2 Volume fields, thus piping to head/tail to get the $SINK + 1'th line will not work.( I have experienced this irl, i'm not just nitpicking)

My solution works based on the assumption that pacmd will always list sinks in a specific order. If you want a more reliable solution, you need to parse the output.

#!/bin/sh

# Get the index of the selected sink:
getsink() {
    pacmd list-sinks |
        awk '/index:/{i++} /* index:/{print i; exit}'
}

# Get the selected sink volume
getvolume() {
    pacmd list-sinks |
        awk '/^\svolume:/{i++} i=='$(getsink)'{print $5; exit}'
}

getvolume

Note: I don't know whether volume fields differ, mine looks like this (from pacmd list-sinks):

volume: front-left: 42706 /  65% / -11.16 dB,   front-right: 42706 /  65% / -11.16 dB

Also I'm only getting the volume of the first channel (front-left) in percentage format (i.e., field 5), your channels may be at different levels.


EDIT:

On second thought you probably actually want to get the default sink name from pacmd stat for a less convoluted solution:

#!/bin/sh
getdefaultsinkname() {
    pacmd stat | awk -F": " '/^Default sink name: /{print $2}'
}

getdefaultsinkvol() {
    pacmd list-sinks |
        awk '/^\s+name: /{indefault = $2 == "<'$(getdefaultsinkname)'>"}
            /^\s+volume: / && indefault {print $5; exit}'

}

setdefaulsinkvol() {
    pactl set-sink-volume $(getdefaultsinkname) $1
}
Shivanshu
  • 17
  • 4
jgr
  • 301
  • 3
  • 4
  • 1
    Thanks! Your second solution works great. However, I think setdefaulsinkvol() needs to be `pactl set-sink-volume $(getdefaultsinkname) "$1"` – MountainX Apr 29 '18 at 07:37
5

for getting a volume I'm trying this one:

echo `(pactl list sinks | grep "Volume: 0:")| awk '{print $3}'`
Anthon
  • 78,313
  • 42
  • 165
  • 222
kairo
  • 59
  • 1
  • 2
  • 3
    Note: the 'Volume' is native language translated, so it would work only for english systems. –  Oct 30 '14 at 20:35
  • 3
    If you have multiple sinks this will give multiple lines of output. – tremby Nov 02 '14 at 10:05
5

Multilingual variant:

pactl list sink-inputs | \
grep -A15 -P "(\#|№)$SINK" | \
grep -P "\d+\s*\/\s*\d+\%" | \
head -1 | \
awk "{print \$5}"

Tested on pactl 5.0

Peter
  • 51
  • 1
  • 1
5

As I can't comment yet (signed up specifically to improve on @jgr's answer), in the case that your default sink is a plugin (like any number of ladspa plugins) his edit solution will return XX%, (note the trailing comma), so this works a bit better than that. Sorry, my awk-fu is very basic, I'm sure there's a better way to do this.

The modified solution also omits the '%' as I don't see the point in keeping it, and if we return just the number we can use it in maths. Also fixed the setvol case, which needs specific instructions in my case.

#/bin/sh
getdefaultsinkname() {
    pacmd stat | awk -F": " '/^Default sink name: /{print $2}'
}

getdefaultsinkvol() {
    pacmd list-sinks |
        awk '/^\s+name: /{indefault = $2 == "<'$(getdefaultsinkname)'>"}
            /^\s+volume: / && indefault {print $5; exit}' |
        awk -F"%" '{print $1}'
}

setdefaultsinkvol() {
    pactl -- set-sink-volume $(getdefaultsinkname) $1
}
Ng Oon-Ee
  • 171
  • 1
  • 4
4

This might actually be implemented as part of the pulseaudio pactl command at some point in the future (seen from January 2021). Non-complete list of places where progress might be tracked:

4

If you have PulseAudio 15.0 or later, it includes the command get-sink-volume, which can be used to do this fairly cleanly.

We'll use @DEFAULT_SINK@ to get the default sink, this is probably what you want unless you've set your software specifically not to use the default. Then we'll use the output of that for the argument for get-sink-volume. After this, we just grep the output to pull out the volume percentage, then use head to only take one of the results.

pactl get-sink-volume @DEFAULT_SINK@ | grep -Po '\d+(?=%)' | head -n 1

The way the command above is written assumes that the left and right speaker are the same volume, however you may need to tailor it if that's not the case for you.

Context

It was merged in a PR to PulseAudio in December 7th 2020.

https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/430

For Debian Users

At the time of writing this comment, DebianStable is still only on PulseAudio 14, however if you're willing to switch your repos to DebianTesting, you can use PulseAudio 16.

Seth Falco
  • 97
  • 9
3

You can use amixer to read the pulseaudio volume by using the mixer option like this.

$ amixer -c $CARD -M -D $MIXER get $SCONTROL
# CARD is your sound card number, mixer is either alsa or pulse and scontrol is the alsa device name, Master if you want to use pulse.
$ amixer -c 1 -M -D pulse get Master

Simple mixer control 'Master',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 65536
  Mono:
  Front Left: Playback 27662 [42%] [on]
  Front Right: Playback 27662 [42%] [on]

Now we can parse it using grep or sed or perl.

$ amixer -c 1 -M -D pulse get Master | grep -o -E [[:digit:]]+%
Ashhar Hasan
  • 153
  • 7
  • Head's up : Apparently `[[:digit:]]` is a bashism : `zsh: no matches found: [[:digit:]]+%` – yPhil Dec 27 '20 at 23:47
2

I found some of the answers here limited, especially if you have multiple sinks. So I want to share what I've found.

There are a lot of great scripts for "getting" and setting PulseAudio status in the source for pulseaudio-ctl which you can view here.

They've opted to use a tool similar to pactl called pacmd that also comes with PulseAudio. If you take a look at man pacmd you'll find that it can be "used to introspect or reconfigure a running PulseAudio sound server during runtime" (pacmd man page). This "introspection" is what we're after here.

Get Current Volume

pacmd list-sinks|grep -A 15 '* index'| awk '/volume: front/{ print $5 }' | sed 's/[%|,]//g'

The function from the repo is a little more verbose depending on the environment: get current volume

Get muted status

You may also want to get the muted status:

pacmd list-sinks|grep -A 15 '* index'|awk '/muted:/{ print $2 }'

View here: get muted status


Script away!

This opens up a lot of opportunity to script with libnotify (as the library does) and print the new volume level or the ability to implement with some other hook, such as playing a sound when you change the volume.

change-volume.sh:

SINK=$(pacmd list-sinks|awk '/\* index:/{ print $3 }') || "@DEFAULT_SINK@"
pactl set-sink-volume "$SINK" "$@"
canberra-gtk-play -i audio-volume-change -d "$(basename "$0")"

. change-volume.sh +5%

brettinternet
  • 235
  • 2
  • 9
2
pactl list sinks | tr ' ' '\n' | grep -m1 '%'

Or trim the percent off the end:

pactl list sinks | tr ' ' '\n' | grep -m1 '%' | tr -d '%'
jbrock
  • 1,111
  • 1
  • 14
  • 23
0

the code below works for three digits volumes (e.g. 120%)

shows the volume of the right speaker:

$ pactl list sinks | grep '^[[:space:]]Volume:' | head -n 1 | sed 's|.*[[:space:]]\([[:digit:]]\+%\).*|\1|'
130%

shows the volume of both speakers:

$ pactl list sinks | grep '^[[:space:]]Volume:' | head -n 1 | sed 's|.*[[:space:]]\([[:digit:]]\+%\).*[[:space:]]\([[:digit:]]\+%\).*|\1 \2|'
130% 130%
user3804598
  • 189
  • 1
  • 6
0

I know this is an old question, but I don't think this was ever answered.

I can easily get the volume of the front-left speaker with

pactl get-sink-volume @DEFAULT_SINK@ | awk 'NR==1{print $5}'

If you are using speakers that will never change volume between the different speakers, this should be good enough.

0

To change each individual channel, and after having looked everywhere, I finally found it!!

amixer -D pulse sset Master 100% = all speakers to 100%

amixer -D pulse sset Master Front 100% = front 100% (or whatever you specify)

amixer -D pulse sset Master Front 100%,50% = front left 100% , front right 50 %

So the same goes for Master Center, Master Rear, Master Side, Master Woofer

This took a very long time but finally I got it

Johan D.
  • 1
  • 1
  • You seem to be answering a different question; this question is about retrieving a PA sink’s volume, not setting an ALSA channel. – Stephen Kitt Jan 11 '23 at 06:29