Bug 77108

Summary: pactl parse_volume() cannot read negatives
Product: PulseAudio Reporter: nguenthe+freedesktopbugzilla
Component: toolsAssignee: pulseaudio-bugs
Status: RESOLVED FIXED QA Contact: pulseaudio-bugs
Severity: blocker    
Priority: medium CC: lennart
Version: unspecified   
Hardware: All   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:

Description nguenthe+freedesktopbugzilla 2014-04-06 15:35:40 UTC
I cannot find a way with pulse to reduce the volume from the command line. I found that the manpage claims
> If the volume specification start with a + or - 
> the volume adjustment will be relative to the current sink volume.

But it does not work:
[me@galleon ~]$ pactl set-sink-volume 0 -10%
pactl: invalid option -- '1'

However this is fine:
[me@galleon ~]$ pactl set-sink-volume 0 +10%

parse_volume() should work, afterall http://cgit.freedesktop.org/pulseaudio/pulseaudio/tree/src/utils/pactl.c#n1476 says
> *vol_flags = (pa_startswith(vs, "+") || pa_startswith(vs, "-")) ? VOL_RELATIVE : VOL_ABSOLUTE;

I believe the problem is this line http://cgit.freedesktop.org/pulseaudio/pulseaudio/tree/src/utils/pactl.c#n1599: getopt is parsing (and choking) on the - before parse_volume() ever gets it.

I have the most recent PA; this is my PA version info:
[kousu@galleon ~]$ pacman -Qi pulseaudio
Name           : pulseaudio
Version        : 5.0-1
Description    : A featureful, general-purpose sound server
Architecture   : x86_64
URL            : http://www.freedesktop.org/wiki/Software/PulseAudio
Licenses       : LGPL  AGPL3
Groups         : None
Provides       : None
Depends On     : libpulse=5.0-1  rtkit  libltdl  speex  tdb  fftw  orc  libsamplerate  webrtc-audio-processing  sbc
Optional Deps  : pulseaudio-alsa: ALSA configuration (recommended) [installed]
                 avahi: zeroconf publishing and discovery [installed]
                 bluez: Bluetooth [installed]
                 bluez-libs: Bluetooth [installed]
                 gconf: paprefs configuration [installed]
                 jack2-dbus: JACK support
                 lirc-utils: IR control [installed]
                 openssl: RAOP (AirPlay) output [installed]
                 python-pyqt4: Equalizer GUI (qpaeq) [installed]
                 xenstore: Xen paravirtual output
Required By    : gnome-settings-daemon  projectm-pulseaudio  pulseaudio-alsa
Optional For   : fluidsynth  google-talkplugin  lmms  phonon-qt4  speech-dispatcher
Conflicts With : None
Replaces       : None
Installed Size : 5247.00 KiB
Packager       : Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
Build Date     : Mon 03 Mar 2014 03:31:31 PM EST
Install Date   : Sun 30 Mar 2014 05:15:54 PM EDT
Install Reason : Installed as a dependency for another package
Install Script : No
Validated By   : Signature
Comment 1 Tanu Kaskinen 2014-04-07 07:27:34 UTC
You can use "--" like this to avoid the command line parser from interpreting -10% as an option:

    pactl -- set-sink-volume 0 -10%

Requiring "--" is annoying, so this should be fixed anyway.
Comment 2 Peter Meerwald 2014-04-15 09:08:48 UTC
I think this can be easily fixed:

    see getopt(3):
    ""By default, getopt() permutes the contents of argv as it scans, so that
      eventually all the nonoptions are at the end.  Two other modes are also
      implemented.   If  the first character of optstring is '+' or the envi‐
      ronment variable POSIXLY_CORRECT is set, then option  processing  stops
      as soon as a nonoption argument is encountered.  If the first character
      of optstring is '-', then each nonoption argv-element is handled as  if
      it were the argument of an option with character code 1.  (This is used
      by programs that were written to expect options and other argv-elements
      in any order and that care about the ordering of the two.)  The special
      argument "--" forces an end of option-scanning regardless of the  scan‐
      ning mode.""
    
    prepend optstring with '+' to use POSIXLY_CORRECT mode

-    while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) {
+    while ((c = getopt_long(argc, argv, "+s:n:h", long_options, NULL)) != -1) {

posting a patch

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.