Set volume using php exec and amixer
Asked Answered
C

4

15

I wrote a little php script to control the volume of my local machine with alsa:

<?php
# for simplicity and testing it really just executes the command:
echo exec('amixer set Master 5%+') . " \n";

Now when I run this script on command line it works fine:

$ php volume.php 
Front Right: Playback 39226 [60%] [on] 
$ php volume.php 
Front Right: Playback 42503 [65%] [on] 
$ php volume.php 
Front Right: Playback 45780 [70%] [on]

I have music playing and I hear it getting louder.

But when I try to run the script via apache from the browser calling http://localhost/volume.php it doesn't work.

# http://localhost/volume.php
Front Right: Playback 55709 [10%] [on]
# F5
Front Right: Playback 55709 [15%] [on]
# F5
Front Right: Playback 55709 [20%] [on]

Now I hear no change in volume and the percentages seem to be unrelated to the current state. It says 10% - 15% - 20% when it really is still at 70%.

My apache is running as my user so exec('whoami') gives me the username I am logged in with on my shell where everything works fine.

# httpd.conf
User mkt
Group mkt

I'm on Fedora 22.

Probably it's due to the apache2 process environment. Any ideas how to fix this?

UPDATE:

This is the output of aplay -L:

[mkt@localhost ~]$ aplay -L
null
    Discard all samples (playback) or generate zero samples (capture)
pulse
    PulseAudio Sound Server
default
    Default ALSA Output (currently PulseAudio Sound Server)
sysdefault:CARD=Intel
    HDA Intel, ALC888 Analog
    Default Audio Device
front:CARD=Intel,DEV=0
    HDA Intel, ALC888 Analog
    Front speakers
surround21:CARD=Intel,DEV=0
    HDA Intel, ALC888 Analog
    2.1 Surround output to Front and Subwoofer speakers
surround40:CARD=Intel,DEV=0
    HDA Intel, ALC888 Analog
    4.0 Surround output to Front and Rear speakers
surround41:CARD=Intel,DEV=0
    HDA Intel, ALC888 Analog
    4.1 Surround output to Front, Rear and Subwoofer speakers
surround50:CARD=Intel,DEV=0
    HDA Intel, ALC888 Analog
    5.0 Surround output to Front, Center and Rear speakers
surround51:CARD=Intel,DEV=0
    HDA Intel, ALC888 Analog
    5.1 Surround output to Front, Center, Rear and Subwoofer speakers
surround71:CARD=Intel,DEV=0
    HDA Intel, ALC888 Analog
    7.1 Surround output to Front, Center, Side, Rear and Woofer speakers
iec958:CARD=Intel,DEV=0
    HDA Intel, ALC888 Digital
    IEC958 (S/PDIF) Digital Audio Output
hdmi:CARD=NVidia,DEV=0
    HDA NVidia, HDMI 0
    HDMI Audio Output
hdmi:CARD=NVidia,DEV=1
    HDA NVidia, HDMI 1
    HDMI Audio Output
hdmi:CARD=NVidia,DEV=2
    HDA NVidia, HDMI 2
    HDMI Audio Output
hdmi:CARD=NVidia,DEV=3
    HDA NVidia, HDMI 3
    HDMI Audio Output

On command line only default and pulse are working:

amixer -D pulse set Master 5%+
amixer -D default set Master 5%+

With PHP even those two don't work. Anyway... my sound comes from my monitors speakers which is plugged in via hdmi. So I guess the last 4 devices are my candidates. But non of them work.

$ amixer -D hdmi:CARD=NVidia,DEV=0 set Master 5%+
$ amixer -D hdmi:CARD=NVidia,DEV=1 set Master 5%+
$ amixer -D hdmi:CARD=NVidia,DEV=2 set Master 5%+
$ amixer -D hdmi:CARD=NVidia,DEV=3 set Master 5%+

In all four cases it says: (with DEV=[0-3] of course)

ALSA lib control.c:954:(snd_ctl_open_noupdate) Invalid CTL hdmi:CARD=NVidia,DEV=3
amixer: Mixer attach hdmi:CARD=NVidia,DEV=3 error: No such file or directory

UPDATE

Output of aplay -l:

$ aplay -l

**** List of Hardware-Devices (PLAYBACK) ****
Card 0: Intel [HDA Intel], Device 0: ALC888 Analog [ALC888 Analog]
  Sub-Devices: 1/1
  Sub-Device #0: subdevice #0
Card 0: Intel [HDA Intel], Device 1: ALC888 Digital [ALC888 Digital]
  Sub-Devices: 1/1
  Sub-Device #0: subdevice #0
Card 1: NVidia [HDA NVidia], Device 3: HDMI 0 [HDMI 0]
  Sub-Devices: 1/1
  Sub-Device #0: subdevice #0
Card 1: NVidia [HDA NVidia], Device 7: HDMI 1 [HDMI 1]
  Sub-Devices: 0/1
  Sub-Device #0: subdevice #0
Card 1: NVidia [HDA NVidia], Device 8: HDMI 2 [HDMI 2]
  Sub-Devices: 1/1
  Sub-Device #0: subdevice #0
Card 1: NVidia [HDA NVidia], Device 9: HDMI 3 [HDMI 3]
  Sub-Devices: 1/1
  Sub-Device #0: subdevice #0

$ amixer -c0 set Master 5%+
$ amixer -c1 set Master 5%+

Both don't work!

SOLUTION:

Thanks for all the help! The answer though came from https://superuser.com/questions/1069981/set-volume-using-php-exec-and-amixer

putenv("PULSE_SERVER=/run/user/".getmyuid()."/pulse/native");
Chally answered 26/4, 2016 at 14:3 Comment(7)
Did you check that your apache2 process' environment matches yours? amixer may try to access local settings that are not available to it.Atavism
hm... echo exec('echo ${HOME}') outputs the correct path on command line but is empty in browser... so I guess thats the problem? But how to solve this...?Phosphoresce
Could try putenv() possibly, php.net/manual/en/function.putenv.phpRhebarhee
yes... the question is what variables to set... :P I'll try.Phosphoresce
Try adding the (unintuitive) putenv('HOME='. getenv('HOME')); to your script. Most other variables should be working, you might want to compare the phpinfo()-output if something is missing. A suspect could be ALSA_CONFIG_PATH.Ridley
You say Apache is running as your user - but does it run in the same session? amixer uses DBUS... I'm blurry on the details, but I assume DBUS is bound to the session, not the user ID. How and where are you starting apache? Perhaps using a more lightweight http server that you can easily run from the command line would be more appropriate for your purpose. You can even write your own :) station.clancats.com/writing-a-webserver-in-pure-php/#Hillhouse
Addendum: Here's a question relating to sharing a DBUS across sessions of the same user: unix.stackexchange.com/questions/44317/…Hillhouse
A
4

Perhaps amixer isn't addressing the correct DBUS when run from apache. Try setting the DBUS_ADDRESS environment variable by invoking amixer from a shell script that sets the variable before running amixer.

dbus_amixer.sh

#! /bin/bash
DBUS_ADDRESS=`grep -z DBUS_SESSION_BUS_ADDRESS /proc/*/environ 2> /dev/null| sed 's/DBUS/\nDBUS/g' | tail -n 1`
if [ "x$DBUS_ADDRESS" != "x" ]; then
        export $DBUS_ADDRESS
        /usr/bin/amixer set Master 5%+
fi

(Code copied from Running command-line application from PHP as specific user)

amixer.php

<?php
echo exec('dbus_amixer.sh') . " \n";
Anhydrous answered 2/5, 2016 at 3:11 Comment(0)
D
2

Try first running aplay -L and you should get output something like this:

pulse
    PulseAudio Sound Server
sysdefault:CARD=MID
    HDA Intel MID, ALC889 Analog
    Default Audio Device
front:CARD=MID,DEV=0
    HDA Intel MID, ALC889 Analog
    Front speakers
surround21:CARD=MID,DEV=0
    HDA Intel MID, ALC889 Analog
    2.1 Surround output to Front and Subwoofer speakers
...

Identify which of these is your device, then modify your amixer ... command to amixer -D device ..., for example amixer -D surround21:CARD=MID,DEV=0 set Master 5%+.

This may work. If not, try aplay -l (lowercase), and get the card number. Then, for example, if the card number is 1, try amixer -c 1 set Master 5%+.

Dihybrid answered 29/4, 2016 at 18:35 Comment(0)
E
1

You say that your Apache user runs as your command line user. How far does the similarity extend? I notice that you use short path:

echo exec('amixer set Master 5%+')

...given that the user is the same, you might have the wrong path in Apache (PATH settings are not dependent on the user, they're in the user profile, and Apache might load a different profile altogether) - try placing the full path to amixer into the exec:

echo exec('/usr/local/bin/or/whatever/amixer set Master 5%+') . " \n";

Also, for debugging purposes, run shell_exec adding 2>&1 stderr redirect to the command line. This might yield some clue as to what exactly is failing.

You can run a more complex command to set up environment:

exec(`HOME=whatever FLAGS=somethingelse PATH=/usr/local/... /usr/local/bin/amixer... 2>&1`);

To know what the environment variables are, you can log as the user, verify that amixer works, dump the environment into a file:

set > set.txt

and check out set.txt for whatever values could apply to amixer. You can run another similar set from within Apache, and compare the results (actually I think that the environment is accessible also via phpinfo()).

Exclosure answered 1/5, 2016 at 11:38 Comment(0)
G
1

The best and more easy way to get this done is by using xdotool.

<?php
shell_exec("DISPLAY=:0 xdotool key XF86AudioMute");
?>

<?php
shell_exec("DISPLAY=:0 xdotool key XF86AudioRaiseVolume");
?>

<?php
shell_exec("DISPLAY=:0 xdotool key XF86AudioLowerVolume");
?>

I installed xdotool and configured the rc.xml file on ubuntu openbox with

 <!-- Keybinding for Volume management -->
   <keybind key="XF86AudioRaiseVolume">
     <action name="Execute">
       <command>amixer -D pulse set Master 10%+</command>
     </action>
  </keybind>
   <keybind key="XF86AudioLowerVolume">
     <action name="Execute">
       <command>amixer -D pulse set Master 10%-</command>
     </action>
   </keybind>
   <keybind key="XF86AudioMute">
     <action name="Execute">
       <command>amixer -D pulse set Master 100%-</command>
     </action>
  </keybind>

It works like a charm.

Gipps answered 27/3, 2018 at 3:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.