使用PHP exec和amixer设置音量

15

我写了一个小的PHP脚本来控制使用alsa的本地机器的音量:

<?php
# for simplicity and testing it really just executes the command:
echo exec('amixer set Master 5%+') . " \n";
现在当我在命令行上运行这个脚本时,它可以正常工作:
$ 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]

我正在播放音乐,我听到它变得更响了。

但是当我尝试通过浏览器调用 http://localhost/volume.php 运行脚本时,它不起作用。

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

现在我听不到音量的变化,而百分比似乎与当前状态无关。它显示为10% - 15% - 20%,但实际上仍然是70%。

我的apache正在以我的用户身份运行,因此 exec('whoami') 会给出我在shell上登录的用户名,在那里一切正常。

# httpd.conf
User mkt
Group mkt

我正在使用Fedora 22操作系统。

可能是由于apache2进程的环境问题导致的。有什么想法如何解决这个问题吗?

更新:

以下是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

在命令行中,只有默认和脉冲工作:

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

使用PHP即使这两个也不起作用。无论如何,我的声音来自通过HDMI插入的显示器扬声器。因此,我想最后4个设备是我的候选对象。但是它们都不起作用。

$ 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%+
在所有四种情况下,它都说:(当然是使用 DEV=[0-3])
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

更新

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%+

都不起作用!

解决方法:

感谢所有的帮助!答案来源于https://superuser.com/questions/1069981/set-volume-using-php-exec-and-amixer

putenv("PULSE_SERVER=/run/user/".getmyuid()."/pulse/native");

你检查过你的apache2进程环境是否与你的匹配吗?amixer可能会尝试访问不可用的本地设置。 - yk11
嗯...echo exec('echo ${HOME}')在命令行中输出了正确的路径,但在浏览器中为空...所以我猜那就是问题所在?但是如何解决这个问题呢...? - Markus Kottländer
是的...问题是要设置哪些变量... :P 我会尝试。 - Markus Kottländer
1
你说Apache正在以你的用户身份运行 - 但它是否在同一会话中运行?amixer使用DBUS... 我对细节有点模糊,但我认为DBUS绑定到会话而不是用户ID。你是如何在哪里启动Apache的?也许使用更轻量级的HTTP服务器,你可以轻松地从命令行运行,会更适合你的目的。你甚至可以自己编写:http://station.clancats.com/writing-a-webserver-in-pure-php/# - brightbyte
1
附加说明:这里有一个关于在同一用户的会话之间共享DBUS的问题:https://unix.stackexchange.com/questions/44317/reuse-d-bus-sessions-across-login-sessions - brightbyte
显示剩余2条评论
4个回答

4
也许当从 Apache 运行时,amixer 没有正确地连接到 DBUS。尝试通过在一个 shell 脚本中设置环境变量 DBUS_ADDRESS 来调用 amixer,然后再运行 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

(代码来自从PHP作为特定用户运行命令行应用程序)

amixer.php

<?php
echo exec('dbus_amixer.sh') . " \n";

2

首先运行aplay -L命令,你应该会得到以下类似的输出:

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
...

识别哪个是您的设备,然后修改您的amixer ...命令为amixer -D device ...,例如amixer -D surround21:CARD=MID,DEV=0 set Master 5%+

这可能有效。如果不行,请尝试使用aplay -l(小写),并获取卡号。然后,例如,如果卡号是1,请尝试amixer -c 1 set Master 5%+


1
你说你的Apache用户以命令行用户身份运行。相似之处有多少?我注意到你使用了短路径:
echo exec('amixer set Master 5%+')

假设用户相同,您可能在Apache中有错误的路径(PATH设置不依赖于用户,它们在用户配置文件中,并且Apache可能会加载完全不同的配置文件)- 尝试将完整路径放入exec中:amixer

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

此外,为了调试目的,可以运行shell_exec命令,并将2>&1 stderr 重定向到命令行。这可能会提供一些关于失败的具体信息。
您可以运行更复杂的命令来设置环境:
exec(`HOME=whatever FLAGS=somethingelse PATH=/usr/local/... /usr/local/bin/amixer... 2>&1`);

要了解环境变量是什么,您可以作为用户登录,验证amixer是否正常工作,将环境转储到文件中:

set > set.txt

并检查set.txt以获取可能适用于amixer的任何值。您可以在Apache内运行另一个类似的set,并比较结果(实际上我认为环境也可以通过phpinfo()访问)。


1
最好且更容易的方法是使用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");
?>

我在Ubuntu Openbox上安装了xdotool并配置了rc.xml文件。

 <!-- 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>

它像魔法一样运作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接