40

这个问题的灵感来自Can you run GUI apps in a docker container? .

基本思想是运行带有音频和用户界面的应用程序(vlc、firefox、skype...)

我正在使用 pulseaudio 搜索 docker 容器,但我找到的所有容器都在 tcp 上使用 pulseaudio 流式传输。(应用程序的安全沙盒)

在我的情况下,我更喜欢从容器内的应用程序直接播放音频到我的主机 pulseaudio。(没有 ssh 隧道和臃肿的 docker 镜像)

Pulseaudio,因为我的 qt 应用程序正在使用它;)

4

4 回答 4

40

我花了一些时间才发现需要什么。(Ubuntu)

我们从 docker run 命令开始docker run -ti --rm myContainer sh -c "echo run something"

ALSA:
我们需要/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和。但这还不是全部(可能是因为 Ubuntu 以及他们过去的做法)。主机系统和docker 容器中的环境变量必须相同。您可能还需要,因为某些应用程序正在从此处访问机器 ID(可能仅包含指向“真实”机器 ID 的符号链接)。至少您可能需要隐藏的主文件夹来存放一些临时数据(我对此不确定)。/etc/machine-id/run/user/$uid/pulseXDG_RUNTIME_DIR/var/lib/dbus~/.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.
当然,您可以将两者结合在一起并将其与xServerui 转发一起使用,如下所示:https ://stackoverflow.com/a/28971413/2835523

顺便提一下:

  • 您可以在dockerfile
  • 用于uid=$(id -u)获取用户 id 和 gidid -g
  • 用这个 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
于 2015-03-11T11:41:07.917 回答
8

受您发布的链接的启发,我能够创建以下解决方案。它是我能得到的最轻量级的。但是,我不确定它是否 (1) 安全,以及 (2) 是否完全适合您的用例(因为它仍然使用网络)。

  1. 安装paprefs在您的主机系统上,例如sudo apt-get install paprefs在 Ubuntu 机器上使用。
  2. 启动 PulseAudio 首选项,转到“网络服务器”选项卡,然后选中“启用对本地声音设备的网络访问”复选框 [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]。您可以使用[1]找到您的 IP 地址ifconfig和 Pulseaudio 端口。pax11publish
  6. 而已。如果 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. 在容器中,运行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;但是,我还没有对此进行测试。

于 2015-03-11T19:22:48.470 回答
5

在尝试了此处描述的大多数解决方案后,我发现只有网络上的 PulseAudio才能真正起作用。但是,您可以通过保持身份验证使其安全。

  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项目。

于 2015-04-27T10:38:12.903 回答
4

假设 pulseaudio 安装在主机和映像中,只需几个步骤即可通过 tcp 提供 pulseaudio 声音。pulseaudio 不需要重新启动,也不需要在主机或映像中进行任何配置。这样它就包含在x11docker中,不需要 VNC 或 SSH:

首先,找到一个空闲的 tcp 端口

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 daemon 的 ip 地址。我总是发现它是 172.17.42.1/16

ip -4 -o a | grep docker0 | awk '{print $4}'

加载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 run 上,创建环境变量 PULSE_SERVER

docker run -e PULSE_SERVER=tcp:172.17.42.1:$PULSE_PORT yourimage

然后,卸载 tcp 模块。(注意:由于未知原因,卸载此模块可以停止主机上的pulseaudio daemon):

pactl unload-module $PULSE_MODULE_ID

编辑:容器中 ALSA 和 Pulseaudio 的操作方法

于 2016-09-29T21:14:22.570 回答