在docker容器中使用音频运行应用程序

A. *_*xxx 33 audio qt alsa pulseaudio docker

这个问题的灵感来自于您是否可以在docker容器中运行GUI应用程序?.

基本的想法是运行带有音频和ui的应用程序(vlc,firefox,skype,...)

我正在使用pulseaudio搜索docker容器,但我发现所有使用pulseaudio流在tcp上的容器.(应用程序的安全沙箱)

在我的情况下,我会优先从容器内的应用程序直接播放音频到我的主机pulseaudio.(没有ssh隧道和臃肿的docker图像)

Pulseaudio因为我的qt app正在使用它;)

A. *_*xxx 32

我花了一些时间才发现需要什么.(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"`
Run Code Online (Sandbox Code Playgroud)

在没有lxc标志的新docker版本中你应该使用这个:

docker run -ti --rm \
    -v /dev/snd:/dev/snd \
     --privileged \
    myContainer sh -c "echo run something"`
Run Code Online (Sandbox Code Playgroud)

的PulseAudio:
在这里我们需要基本/dev/shm,/etc/machine-id/run/user/$uid/pulse.但这并非全部(可能是因为Ubuntu以及他们过去是如何做到的).envirorment变量XDG_RUNTIME_DIR必须在主机系统和docker 容器中相同.您可能还需要,/var/lib/dbus因为某些应用程序正在从此处访问计算机ID(可能只包含指向"真实"计算机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"
Run Code Online (Sandbox Code Playgroud)

在新的docker版本中,您可能需要添加--privileged.
当然,您可以将它们组合在一起并将其与xServerui转发一起使用,如下所示:https://stackoverflow.com/a/28971413/2835523

仅举几个:

  • 你可以处理大部分(所有没有使用过的id) dockerfile
  • uid=$(id -u)得到的用户ID和GID与id -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
Run Code Online (Sandbox Code Playgroud)

  • ALSA方法对我不起作用。我收到以下错误`ALSA lib pcm_dmix.c:1029:(snd_pcm_dmix_open)无法打开从属服务器`。 (2认同)

Ale*_*lex 9

现在我们有一个 Pipewire,如果您希望 docker 容器内的应用程序使用在主机上运行的 Pipewire 服务器来播放/录制声音,您可以执行以下操作:

  1. 首先,我们显然需要在我们的主机上运行一个 Pipewire 服务器。graphical.target在现代发行版上,当 systemd 到达并执行登录管理器(gdm、sddm 等)时,Pipewire 就会启动。然后,稍后,当用户登录时,Pipewire 将重新启动以归该用户所有。

为了让 docker 容器内的应用程序使用 Pipewire,我们将套接字文件描述符传递给该容器。为此,我们需要知道谁在您的主机上运行 Pipewire 服务器。您可以通过查看管道进程在谁的运行下进行检查,然后找出正确的套接字文件:

testuser@asrock-ubuntu:~$ ps -fp $(pgrep -d, -x pipewire)

UID          PID    PPID  C STIME TTY          TIME CMD
testuser     4250    4206  1 13:32 ?        00:00:27 /usr/bin/pipewire

testuser@asrock-ubuntu:~$ id testuser

uid=1000(testuser) gid=1000(testuser) groups=1000(testuser),4(adm),6(disk),24(cdrom),27(sudo),30(dip),46(plugdev),105(input),107(kvm),122(lpadmin),134(lxd),135(sambashare),140(libvirt),64055(libvirt-qemu),997(docker)
Run Code Online (Sandbox Code Playgroud)

所以在我们的例子中,我希望应该有一个套接字文件/run/user/1000/pipewire-0。去检查一下你的系统。

  1. 现在我们将创建一个轻量级的 Alpine docker 容器,同时将该 Pipewire 套接字文件传递给它并设置 XDG_RUNTIME_DIR 变量,这是容器内的 Pipewire 客户端所需的。
docker run -it -v /run/user/1000/pipewire-0:/tmp/pipewire-0 -e XDG_RUNTIME_DIR=/tmp --rm alpine /bin/ash
Run Code Online (Sandbox Code Playgroud)
  1. 在容器内部,我们安装一些软件包,以使整个过程正常工作:
  • alsa-utils - 提供一组我们将用作示例软件的 ALSA 实用程序,这需要 ALSA
  • Pipewire - Pipewire 服务器(和客户端)二进制文件。但我们不会在容器中运行成熟的服务器,根本不会,我们只需要它的客户端部分在那里
  • pipeline-alsa - 引入了一个虚拟 ALSA 设备“pipewire”,我们将在我们的软件中使用它,这需要 ALSA。简单来说,这是 ALSA 和我们的 Pipewire 客户端之间的桥梁
apk add pipewire-alsa pipewire alsa-utils
Run Code Online (Sandbox Code Playgroud)
  1. 现在让我们测试一下是否一切正常。确保您在运行时看到“pipewire”设备aplay -L,然后运行我们的简单测试以通过该设备播放一些噪音:
speaker-test -Dpipewire -c2
Run Code Online (Sandbox Code Playgroud)

此时您应该听到声音。如果没有,请检查主机上的默认 Pipewire 接收器设备。如果您正在运行 Gnome,请打开 Gnome 设置 -> 声音 -> 输出

在容器内,我们现在可以使用 arecord 录制波形文件并使用纯 ALSA 工具进行回放:

arecord --duration=5 --device=pipewire test.wav
aplay --device=pipewire test.wav
Run Code Online (Sandbox Code Playgroud)
  1. 最后一件事,在我们开始之前 - 让我们还检查一下本机 pipeline 客户端是否可以在该容器内执行。为此,我们安装pipewire-tools. 我要播放的示例 wav 文件与alsa-utils我们之前安装的 pacakge 一起提供:
apk add pipewire-tools
pw-play /usr/share/sounds/alsa/Rear_Center.wav
Run Code Online (Sandbox Code Playgroud)

简而言之,整体设置是这样的:

结果设置


cti*_*tze 5

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

  1. paprefs在主机系统上安装,例如sudo apt-get install paprefs在Ubuntu计算机上使用。
  2. 启动PulseAudio首选项,转到“网络服务器”选项卡,然后选中“启用对本地声音设备的网络访问”复选框[1]
  3. 重启你的电脑。(仅重启Pulseaudio在Ubuntu 14.10上对我不起作用)
  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使用pax11publish[1] 查找IP地址,使用Pulseaudio端口查找。
  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; 我还没有测试过。


Wer*_*ght 5

在尝试了此处描述的大多数解决方案后,我发现只有网络上的 PulseAudio真正有效。但是,您可以通过保留身份验证来确保安全。

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

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

  3. 重新启动 PulseAudio:

    $ service pulseaudio restart
    
    Run Code Online (Sandbox Code Playgroud)
  4. 检查它是否有效或重新启动机器:

    $ (pax11publish || xprop -root PULSE_SERVER) | grep -Eo 'tcp:[^ ]*'
    tcp:myhostname:4713
    
    Run Code Online (Sandbox Code Playgroud)

现在使用该套接字:

$ docker run \
    -e PULSE_SERVER=tcp:$(hostname -i):4713 \
    -e PULSE_COOKIE=/run/pulse/cookie \
    -v ~/.config/pulse/cookie:/run/pulse/cookie \
    ...
Run Code Online (Sandbox Code Playgroud)

检查容器内运行的用户是否有权访问 cookie 文件~/.config/pulse/cookie

要测试它的工作原理:

$ apt-get install mplayer
$ mplayer /usr/share/sounds/alsa/Front_Right.wav
Run Code Online (Sandbox Code Playgroud)

更多信息可以查看Docker Mopidy项目。