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

zrfyljdw  于 2023-03-01  发布在  Docker
关注(0)|答案(5)|浏览(377)

这个问题的灵感来自于Can you run GUI apps in a docker container?
基本的想法是运行带有音频和用户界面的应用程序(VLC,Firefox,Skype,...)
我正在搜索使用pulseaudio的docker容器,但是我找到的所有容器都是通过tcp使用pulseaudio流的。(应用程序的安全沙箱)

在我的例子中,我更喜欢从容器中的应用程序直接播放音频到我的主机pulseaudio(没有ssh隧道和臃肿的docker图像)。
PulseAudio,因为我的QT应用程序正在使用它;)

9lowa7mx

9lowa7mx1#

我花了一些时间才发现需要什么。(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"`

脉冲音频:
更新:它可能是enought到挂载这pulseaudio套接字在这容器之内使用-v选项.这取决于你的版本和prefered存取方法.见其他的回答为这套接字方法.
这里我们需要/dev/shm``/etc/machine-id/run/user/$uid/pulse。但这还不是全部(可能是因为Ubuntu和他们过去的做法)环境变量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"

在新的docker版本中,您可能需要添加--privileged
当然,您可以将两者结合起来,并将其与xServer ui转发一起使用,如下所示:https://stackoverflow.com/a/28971413/2835523
仅提一下:

  • 您可以在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
mitkmikd

mitkmikd2#

受你所张贴的链接的启发,我能够创建下面的解决方案。它是我所能得到的最轻量级的。但是,我不确定它是否(1)安全,以及(2)完全适合你的用例(因为它仍然使用网络)。
1.在您的主机系统上安装paprefs,例如在Ubuntu机器上使用sudo apt-get install paprefs
1.启动PulseAudio首选项,转到“网络服务器”选项卡,并选中“启用对本地声音设备的网络访问”复选框[1]
1.重新启动你的电脑。(只有重新启动Pulseaudio没有为我在Ubuntu 14.10工作)
1.将Pulseaudio安装在容器中,例如sudo apt-get install -y pulseaudio
1.在容器中,运行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端口。
1.如果IP地址和Pulseaudio端口可能会更改,那么步骤5可能会自动执行。另外,我不确定Docker是否会永久存储PULSE_SERVER这样的环境变量:如果没有,那么你必须在每个容器启动后初始化它。
如果能提出改进我的方法的建议,我将不胜感激,因为我目前正在处理一个与OP类似的问题。
参考文献:
[1][https://github.com/jlund/docker-chrome-pulseaudio](https://github.com/jlund/docker-chrome-pulseaudio)
[2][https://github.com/jlund/docker-chrome-pulseaudio/blob/master/Dockerfile](https://github.com/jlund/docker-chrome-pulseaudio/blob/master/Dockerfile)
更新(可能是更好的解决方案):
使用Unix套接字而不是TCP套接字也可以实现此功能:
1.使用-v /run/user/$UID/pulse/native:/path/to/pulseaudio/socket启动容器
1.在容器中,运行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;我还没有测试过这个。

pn9klfpd

pn9klfpd3#

在尝试了这里描述的大多数解决方案后,我发现只有PulseAudio over Network才能真正工作。不过,您可以通过保持身份验证来确保它的安全。
1.安装paprefs(在主机上):

$ apt-get install paprefs

1.启动paprefs(PulseAudio首选项)〉网络服务器〉[X]启用对本地声音设备的网络访问。
1.重启脉冲音频:

$ service pulseaudio restart

1.检查其是否工作或重启机器:

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

f0ofjuux

f0ofjuux4#

假设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 $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运行时,创建环境变量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

6psbrbz9

6psbrbz95#

我设法用以下方法停靠了一个Java游戏,有效地传递了游戏的声音。
这种方法需要构建映像,确保应用程序具有所需的所有依赖项,在本例中为pulseaudio和x11。如果您确定映像具有所需的一切,则可以按照前面的答案继续操作。
在这里,我们需要构建映像,然后才能真正启动它。

docker build -t my-unciv-image . # Run from directory where Dockerfile is
docker run --name unciv # image name\ 
  --device /dev/dri \
  -e DISPLAY=$DISPLAY \
  -e PULSE_SERVER=unix:/run/user/1000/pulse/native \
  --privileged \
  -u $(id -u):$(id -g) \
  -v /path/to/Unciv:/App \
  -v /run/user/$(id -u)/pulse:/run/user/(id -u)/pulse \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -w /App \
  my-unciv-image \
  java -jar /App/Unciv.jar

在第二个命令中指定以下内容:

  • --name:为容器指定名称
  • --device:视频设备 *
  • -e:所需的环境变量
  • DISPLAY:显示编号
  • PULSE_SERVER:PulseAudio音频服务器插座
  • --privileged:运行ip privileged *,以便它可以访问所有设备
  • -v:已装入的卷:
  • 装载到容器中/App的游戏的路径**
  • 音频服务器插座
  • 显示服务器插座
  • -w:工作目录

下面是它的一个docker-compose.yml版本:
x一个一个一个一个x一个一个二个x
注:

    • 只有游戏或任何使用openGL的东西才需要。要么显式传递设备,要么以特权运行它,但我认为传递设备就足够了,使它成为特权可能是矫枉过正。
      • 此数学公式可能与Docker映像捆绑在一起,但仅用于演示。
  • 对于音频,需要传递env变量PULSE_SERVER并挂载pulseaudio插座

相关问题