【问题标题】:run apps using audio in a docker container在 docker 容器中使用音频运行应用程序
【发布时间】:2015-05-13 04:32:29
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: qt audio docker alsa pulseaudio


    【解决方案1】:

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

    【讨论】:

    • 不幸的是,--lxc-conf 选项在 2014 年被删除。github.com/docker/docker/pull/5797
    • 我还没有测试过,但我猜这个参数有替代品。 --privileged、--cap-add、-cgroup-parent 和 --device 可以工作
    • -v /dev/snd:/dev/snd --特权有效!检查:github.com/pwasiewi/docker-freeciv-client
    • ALSA 方法对我不起作用。我收到以下错误ALSA lib pcm_dmix.c:1029:(snd_pcm_dmix_open) unable to open slave
    • 为我工作!但是,Jack Audio 运气好吗?
    【解决方案2】:

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

    1. 在您的主机系统上安装paprefs,例如在 Ubuntu 机器上使用 sudo apt-get install paprefs
    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]。您可以使用 ifconfig 找到您的 IP 地址,使用 pax11publish [1] 找到 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;不过我还没有测试过。

    【讨论】:

    • 这个想法是让它在不更改区域设置 PulseAudio 首选项(并且不使用网络连接)的情况下工作。但感谢您的信息
    • 您还需要设置pulse cookie,以便您获得主机pulseaudio的授权。基本上, -v $HOME/.config/pulse/cookie:/run/pulse/cookie:ro 什么的。但是,将 $PULSE_COOKIE 更改为指向 /run/pulse/cookie 对我不起作用,因为绑定是只读的,然后脉冲回退到 ~/.config/pulse/cookie。所以我做了 ln -fs /run/pulse/cookie ~/.config/pulse/cookie 就是这样。
    • 我不需要映射脉冲 cookie。也许是因为我已经使用主机 uid:gid 运行容器?
    【解决方案3】:

    在尝试了此处描述的大多数解决方案后,我发现只有 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项目。

    【讨论】:

      【解决方案4】:

      假设 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 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
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-17
        • 2020-12-30
        相关资源
        最近更新 更多