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.

5
  • pactl list sinks gives you the volume, but not in a nice easy format like set-sink-volume.
    – derobert
    May 27, 2014 at 16:05
  • 2
    There's a question on Ask Ubuntu with an answer giving a nice perl-oneliner to parse the volume out of this. May 27, 2014 at 16:23
  • @derobert Thanks, I'll just grep and/or sed it out of there!
    – Higemaru
    May 28, 2014 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, 2014 at 11:51
  • @derobert - getting this issue - Connection failure: Connection refused pa_context_connect() failed: Connection refused Feb 18, 2021 at 13:18

14 Answers 14

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}%
4
  • 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, 2017 at 6: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. Aug 8, 2019 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}') Nov 25, 2019 at 11:50
  • @MariusGedminas: Alternatively, pacmd list-sinks seems to output everything in English, regardless of the user's language.
    – balu
    Jan 27, 2020 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
4
  • 6
    In Debian, you can use the pulsemixer package. It looks about the same. Nov 5, 2018 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, 2020 at 18:30
  • @balu It uses percentages by default.
    – Bogdan M.
    Jan 9, 2021 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 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
}
1
  • 1
    Thanks! Your second solution works great. However, I think setdefaulsinkvol() needs to be pactl set-sink-volume $(getdefaultsinkname) "$1"
    – MountainX
    Apr 29, 2018 at 7:37
6

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.

5

for getting a volume I'm trying this one:

echo `(pactl list sinks | grep "Volume: 0:")| awk '{print $3}'`
2
  • 3
    Note: the 'Volume' is native language translated, so it would work only for english systems.
    – user89156
    Oct 30, 2014 at 20:35
  • 3
    If you have multiple sinks this will give multiple lines of output.
    – tremby
    Nov 2, 2014 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

1
  • 1
    Can you add an explanation?
    – Codebling
    Oct 25, 2019 at 22:00
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
}
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:

1
  • Thanks for putting this here. That's good news!
    – Higemaru
    Jan 18, 2021 at 13:31
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:]]+%
1
  • Head's up : Apparently [[:digit:]] is a bashism : zsh: no matches found: [[:digit:]]+%
    – yPhil
    Dec 27, 2020 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%

2
pactl list sinks | tr ' ' '\n' | grep -m1 '%'

Or trim the percent off the end:

pactl list sinks | tr ' ' '\n' | grep -m1 '%' | tr -d '%'
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%
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.

1
  • Back then there was no pactl get-sink-volume. It's good to know it got implemented.
    – Higemaru
    Dec 19, 2022 at 10:14
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

1
  • You seem to be answering a different question; this question is about retrieving a PA sink’s volume, not setting an ALSA channel. Jan 11 at 6:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .