运行 应用在 docker 容器中使用音频
run apps using audio in a docker container
这个问题的灵感来自Can you run GUI apps in a docker container?。
基本思路是 运行 带音频的应用程序和 ui(vlc、firefox、skype 等)
我正在搜索 docker 使用 pulseaudio 的容器,但我发现所有容器都使用 pulseaudio 通过 tcp 流式传输。
(应用程序的安全沙盒)
- https://gist.github.com/hybris42/ce429de428e5af3a344a
- https://github.com/jlund/docker-chrome-pulseaudio
- https://github.com/tomparys/docker-skype-pulseaudio
在我的例子中,我更喜欢从容器内的应用程序直接播放音频到我的主机 pulseaudio。 (没有 ssh 隧道和臃肿的 docker 图片)
Pulseaudio,因为我的 qt 应用程序正在使用它 ;)
我花了一些时间才找到需要的东西。 (Ubuntu)
我们从 docker 运行 命令开始 docker run -ti --rm myContainer sh -c "echo run something"
阿尔萨:
我们需要 /dev/snd
和一些硬件访问权限。
当我们把它放在一起时,我们有
docker run -ti --rm \
-v /dev/snd:/dev/snd \
--lxc-conf='lxc.cgroup.devices.allow = c 116:* rwm' \
myContainer sh -c "echo run something"`
在没有 lxc 标志的新 docker 版本中你应该使用这个:
docker run -ti --rm \
-v /dev/snd:/dev/snd \
--privileged \
myContainer sh -c "echo run something"`
PULSEAUDIO:
更新:使用 -v 选项在容器中安装 pulseaudio 套接字可能就足够了。这取决于您的版本和首选访问方法。查看套接字方法的其他答案。
这里基本上需要/dev/shm
、/etc/machine-id
和/run/user/$uid/pulse
。但这还不是全部(可能是因为 Ubuntu 以及他们过去是如何做到的)。主机系统和 docker 容器中的环境变量 XDG_RUNTIME_DIR
必须相同。您可能还需要 /var/lib/dbus
,因为某些应用程序正在从此处访问机器 ID(可能仅包含符号 link 到 'real' 机器 ID)。至少你可能需要隐藏的主文件夹 ~/.pulse
来存放一些临时数据(我不确定)。
docker run -ti --rm \
-v /dev/shm:/dev/shm \
-v /etc/machine-id:/etc/machine-id \
-v /run/user/$uid/pulse:/run/user/$uid/pulse \
-v /var/lib/dbus:/var/lib/dbus \
-v ~/.pulse:/home/$dockerUsername/.pulse \
myContainer sh -c "echo run something"
在新的 docker 版本中,您可能需要添加 --privileged
。
当然,您可以将两者结合起来并与 xServer
ui 转发一起使用,如下所示:
顺便提一下:
- 您可以在
dockerfile
中处理其中的大部分(所有这些都没有使用过的 ID)
- 使用
uid=$(id -u)
使用 id -g
获取用户 ID 和 gid
- 使用此 ID 创建一个 docker 用户
创建用户脚本:
mkdir -p /home/$dockerUsername && \
echo "$dockerUsername:x:${uid}:${gid}:$dockerUsername,,,:/home/$dockerUsername:/bin/bash" >> /etc/passwd && \
echo "$dockerUsername:x:${uid}:" >> /etc/group && \
mkdir /etc/sudoers.d && \
echo "$dockerUsername ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$dockerUsername && \
chmod 0440 /etc/sudoers.d/$dockerUsername && \
chown ${uid}:${gid} -R /home/$dockerUsername
受您发布的链接的启发,我能够创建以下解决方案。它尽可能轻巧。但是,我不确定它是否 (1) 安全,以及 (2) 是否完全适合您的用例(因为它仍在使用网络)。
- 在您的主机系统上安装
paprefs
,例如在 Ubuntu 机器上使用 sudo apt-get install paprefs
。
- 启动 PulseAudio 首选项,转到 "Network Server" 选项卡,然后选中 "Enable network access to local sound devices" 复选框 [1]
- 重新启动计算机。 (在 Ubuntu 14.10 上仅重启 Pulseaudio 对我不起作用)
- 在您的容器中安装 Pulseaudio,例如
sudo apt-get install -y pulseaudio
- 在您的容器中,运行
export "PULSE_SERVER=tcp:<host IP address>:<host Pulseaudio port>"
。例如,export "PULSE_SERVER=tcp:172.16.86.13:4713"
[2]。您可以使用 ifconfig
找到您的 IP 地址,使用 pax11publish
[1]. 找到 Pulseaudio 端口
- 就是这样。如果 IP 地址和 Pulseaudio 端口可能会发生变化,则第 5 步可能应该自动执行。此外,我不确定 Docker 是否永久存储环境变量,如
PULSE_SERVER
:如果没有,则必须在每个容器启动后对其进行初始化。
非常感谢能改进我的方法的建议,因为我目前正在处理与 OP 类似的问题。
参考文献:
[1] https://github.com/jlund/docker-chrome-pulseaudio
[2] https://github.com/jlund/docker-chrome-pulseaudio/blob/master/Dockerfile
更新(可能是更好的解决方案):
这也适用于使用 Unix 套接字而不是 TCP 套接字:
- 用
-v /run/user/$UID/pulse/native:/path/to/pulseaudio/socket
启动容器
- 在容器中,运行
export "PULSE_SERVER=unix:/path/to/pulseaudio/socket"
/path/to/pulseaudio/socket
可以是任何东西,出于测试目的我使用了/home/user/pulse
。
也许它甚至可以使用与主机相同的路径(处理 $UID 部分)作为默认套接字,这样最终的解决方案将是 -v /run/user/$UID/pulse/native:/run/user/<UID in container>/pulse
;不过我还没有测试过。
在尝试了此处描述的大部分解决方案后,我发现只有 PulseAudio over network 真正有效。但是,您可以通过保留身份验证来保证安全。
安装 paprefs(在主机上):
$ apt-get install paprefs
启动 paprefs
(PulseAudio 首选项)> 网络服务器 > [X] 启用对本地声音设备的网络访问。
重启 PulseAudio:
$ service pulseaudio restart
检查是否有效或重启机器:
$ (pax11publish || xprop -root PULSE_SERVER) | grep -Eo 'tcp:[^ ]*'
tcp:myhostname:4713
现在使用那个套接字:
$ docker run \
-e PULSE_SERVER=tcp:$(hostname -i):4713 \
-e PULSE_COOKIE=/run/pulse/cookie \
-v ~/.config/pulse/cookie:/run/pulse/cookie \
...
检查容器内的用户 运行 是否可以访问 cookie 文件 ~/.config/pulse/cookie
。
要测试它是否有效:
$ apt-get install mplayer
$ mplayer /usr/share/sounds/alsa/Front_Right.wav
有关更多信息,请查看 Docker Mopidy 项目。
假设 pulseaudio 安装在主机和映像中,只需几步即可通过 tcp 提供 pulseaudio 声音。 pulseaudio 不需要重新启动,也不需要在主机或图像中进行任何配置。这样它就包含在 x11docker 中,不需要 VNC 或 SSH:
read LOWERPORT UPPERPORT < /proc/sys/net/ipv4/ip_local_port_range
while : ; do
PULSE_PORT="`shuf -i $LOWERPORT-$UPPERPORT -n 1`"
ss -lpn | grep -q ":$PULSE_PORT " || break
done
获取 docker 守护程序的 IP 地址。我总是发现它是 172.17.42.1/16
ip -4 -o a | grep docker0 | awk '{print }'
加载 pulseaudio tcp 模块,验证与 docker ip:
的连接
PULSE_MODULE_ID=$(pactl load-module module-native-protocol-tcp port=$PULSE_PORT auth-ip-acl=172.17.42.1/16)
在 docker 运行 上,创建环境变量 PULSE_SERVER
docker run -e PULSE_SERVER=tcp:172.17.42.1:$PULSE_PORT yourimage
之后,卸载tcp模块。 (注意:由于未知原因,卸载此模块可以停止主机上的 pulseaudio 守护进程):
pactl unload-module $PULSE_MODULE_ID
这个问题的灵感来自Can you run GUI apps in a docker container?。
基本思路是 运行 带音频的应用程序和 ui(vlc、firefox、skype 等)
我正在搜索 docker 使用 pulseaudio 的容器,但我发现所有容器都使用 pulseaudio 通过 tcp 流式传输。 (应用程序的安全沙盒)
- https://gist.github.com/hybris42/ce429de428e5af3a344a
- https://github.com/jlund/docker-chrome-pulseaudio
- https://github.com/tomparys/docker-skype-pulseaudio
在我的例子中,我更喜欢从容器内的应用程序直接播放音频到我的主机 pulseaudio。 (没有 ssh 隧道和臃肿的 docker 图片)
Pulseaudio,因为我的 qt 应用程序正在使用它 ;)
我花了一些时间才找到需要的东西。 (Ubuntu)
我们从 docker 运行 命令开始 docker run -ti --rm myContainer sh -c "echo run something"
阿尔萨:
我们需要 /dev/snd
和一些硬件访问权限。
当我们把它放在一起时,我们有
docker run -ti --rm \
-v /dev/snd:/dev/snd \
--lxc-conf='lxc.cgroup.devices.allow = c 116:* rwm' \
myContainer sh -c "echo run something"`
在没有 lxc 标志的新 docker 版本中你应该使用这个:
docker run -ti --rm \
-v /dev/snd:/dev/snd \
--privileged \
myContainer sh -c "echo run something"`
PULSEAUDIO:
更新:使用 -v 选项在容器中安装 pulseaudio 套接字可能就足够了。这取决于您的版本和首选访问方法。查看套接字方法的其他答案。
这里基本上需要/dev/shm
、/etc/machine-id
和/run/user/$uid/pulse
。但这还不是全部(可能是因为 Ubuntu 以及他们过去是如何做到的)。主机系统和 docker 容器中的环境变量 XDG_RUNTIME_DIR
必须相同。您可能还需要 /var/lib/dbus
,因为某些应用程序正在从此处访问机器 ID(可能仅包含符号 link 到 'real' 机器 ID)。至少你可能需要隐藏的主文件夹 ~/.pulse
来存放一些临时数据(我不确定)。
docker run -ti --rm \
-v /dev/shm:/dev/shm \
-v /etc/machine-id:/etc/machine-id \
-v /run/user/$uid/pulse:/run/user/$uid/pulse \
-v /var/lib/dbus:/var/lib/dbus \
-v ~/.pulse:/home/$dockerUsername/.pulse \
myContainer sh -c "echo run something"
在新的 docker 版本中,您可能需要添加 --privileged
。
当然,您可以将两者结合起来并与 xServer
ui 转发一起使用,如下所示:
顺便提一下:
- 您可以在
dockerfile
中处理其中的大部分(所有这些都没有使用过的 ID)
- 使用
uid=$(id -u)
使用id -g
获取用户 ID 和 gid
- 使用此 ID 创建一个 docker 用户
创建用户脚本:
mkdir -p /home/$dockerUsername && \
echo "$dockerUsername:x:${uid}:${gid}:$dockerUsername,,,:/home/$dockerUsername:/bin/bash" >> /etc/passwd && \
echo "$dockerUsername:x:${uid}:" >> /etc/group && \
mkdir /etc/sudoers.d && \
echo "$dockerUsername ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$dockerUsername && \
chmod 0440 /etc/sudoers.d/$dockerUsername && \
chown ${uid}:${gid} -R /home/$dockerUsername
受您发布的链接的启发,我能够创建以下解决方案。它尽可能轻巧。但是,我不确定它是否 (1) 安全,以及 (2) 是否完全适合您的用例(因为它仍在使用网络)。
- 在您的主机系统上安装
paprefs
,例如在 Ubuntu 机器上使用sudo apt-get install paprefs
。 - 启动 PulseAudio 首选项,转到 "Network Server" 选项卡,然后选中 "Enable network access to local sound devices" 复选框 [1]
- 重新启动计算机。 (在 Ubuntu 14.10 上仅重启 Pulseaudio 对我不起作用)
- 在您的容器中安装 Pulseaudio,例如
sudo apt-get install -y pulseaudio
- 在您的容器中,运行
export "PULSE_SERVER=tcp:<host IP address>:<host Pulseaudio port>"
。例如,export "PULSE_SERVER=tcp:172.16.86.13:4713"
[2]。您可以使用ifconfig
找到您的 IP 地址,使用pax11publish
[1]. 找到 Pulseaudio 端口
- 就是这样。如果 IP 地址和 Pulseaudio 端口可能会发生变化,则第 5 步可能应该自动执行。此外,我不确定 Docker 是否永久存储环境变量,如
PULSE_SERVER
:如果没有,则必须在每个容器启动后对其进行初始化。
非常感谢能改进我的方法的建议,因为我目前正在处理与 OP 类似的问题。
参考文献:
[1] https://github.com/jlund/docker-chrome-pulseaudio
[2] https://github.com/jlund/docker-chrome-pulseaudio/blob/master/Dockerfile
更新(可能是更好的解决方案):
这也适用于使用 Unix 套接字而不是 TCP 套接字:
- 用
-v /run/user/$UID/pulse/native:/path/to/pulseaudio/socket
启动容器
- 在容器中,运行
export "PULSE_SERVER=unix:/path/to/pulseaudio/socket"
/path/to/pulseaudio/socket
可以是任何东西,出于测试目的我使用了/home/user/pulse
。
也许它甚至可以使用与主机相同的路径(处理 $UID 部分)作为默认套接字,这样最终的解决方案将是 -v /run/user/$UID/pulse/native:/run/user/<UID in container>/pulse
;不过我还没有测试过。
在尝试了此处描述的大部分解决方案后,我发现只有 PulseAudio over network 真正有效。但是,您可以通过保留身份验证来保证安全。
安装 paprefs(在主机上):
$ apt-get install paprefs
启动
paprefs
(PulseAudio 首选项)> 网络服务器 > [X] 启用对本地声音设备的网络访问。重启 PulseAudio:
$ service pulseaudio restart
检查是否有效或重启机器:
$ (pax11publish || xprop -root PULSE_SERVER) | grep -Eo 'tcp:[^ ]*' tcp:myhostname:4713
现在使用那个套接字:
$ docker run \
-e PULSE_SERVER=tcp:$(hostname -i):4713 \
-e PULSE_COOKIE=/run/pulse/cookie \
-v ~/.config/pulse/cookie:/run/pulse/cookie \
...
检查容器内的用户 运行 是否可以访问 cookie 文件 ~/.config/pulse/cookie
。
要测试它是否有效:
$ apt-get install mplayer
$ mplayer /usr/share/sounds/alsa/Front_Right.wav
有关更多信息,请查看 Docker Mopidy 项目。
假设 pulseaudio 安装在主机和映像中,只需几步即可通过 tcp 提供 pulseaudio 声音。 pulseaudio 不需要重新启动,也不需要在主机或图像中进行任何配置。这样它就包含在 x11docker 中,不需要 VNC 或 SSH:
read LOWERPORT UPPERPORT < /proc/sys/net/ipv4/ip_local_port_range
while : ; do
PULSE_PORT="`shuf -i $LOWERPORT-$UPPERPORT -n 1`"
ss -lpn | grep -q ":$PULSE_PORT " || break
done
获取 docker 守护程序的 IP 地址。我总是发现它是 172.17.42.1/16
ip -4 -o a | grep docker0 | awk '{print }'
加载 pulseaudio tcp 模块,验证与 docker ip:
的连接PULSE_MODULE_ID=$(pactl load-module module-native-protocol-tcp port=$PULSE_PORT auth-ip-acl=172.17.42.1/16)
在 docker 运行 上,创建环境变量 PULSE_SERVER
docker run -e PULSE_SERVER=tcp:172.17.42.1:$PULSE_PORT yourimage
之后,卸载tcp模块。 (注意:由于未知原因,卸载此模块可以停止主机上的 pulseaudio 守护进程):
pactl unload-module $PULSE_MODULE_ID