运行 应用在 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 流式传输。 (应用程序的安全沙盒)

在我的例子中,我更喜欢从容器内的应用程序直接播放音频到我的主机 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) 是否完全适合您的用例(因为它仍在使用网络)。

  1. 在您的主机系统上安装 paprefs,例如在 Ubuntu 机器上使用 sudo apt-get install paprefs
  2. 启动 PulseAudio 首选项,转到 "Network Server" 选项卡,然后选中 "Enable network access to local sound devices" 复选框 [1]
  3. 重新启动计算机。 (在 Ubuntu 14.10 上仅重启 Pulseaudio 对我不起作用)
  4. 在您的容器中安装 Pulseaudio,例如sudo apt-get install -y pulseaudio
  5. 在您的容器中,运行 export "PULSE_SERVER=tcp:<host IP address>:<host Pulseaudio port>"。例如,export "PULSE_SERVER=tcp:172.16.86.13:4713" [2]。您可以使用 ifconfig 找到您的 IP 地址,使用 pax11publish [1].
  6. 找到 Pulseaudio 端口
  7. 就是这样。如果 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 套接字:

  1. -v /run/user/$UID/pulse/native:/path/to/pulseaudio/socket
  2. 启动容器
  3. 在容器中,运行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 真正有效。但是,您可以通过保留身份验证来保证安全。

  1. 安装 paprefs(在主机上):

    $ apt-get install paprefs
    
  2. 启动 paprefs(PulseAudio 首选项)> 网络服务器 > [X] 启用对本地声音设备的网络访问。

  3. 重启 PulseAudio:

    $ service pulseaudio restart
    
  4. 检查是否有效或重启机器:

    $ (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:

首先,find a free tcp port

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

编辑:How-To for ALSA and Pulseaudio in container