gpt4 book ai didi

docker : sharing/dev/snd on multiple containers leads to "device or resource busy"

转载 作者:行者123 更新时间:2023-12-04 15:17:38 25 4
gpt4 key购买 nike

adding host device ( --device /dev/snd ) 到 Docker 容器,我有时会遇到 Device or resource busy错误。

例子

我用一个涉及音频的最小示例( alsa )重现了这个问题。这是我的Dockerfile (生成图像 docker-device-example ):

FROM    debian:buster

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
alsa-utils \
&& rm -rf /var/lib/apt/lists/*

我正在运行以下命令( speaker-test 是一个生成可用于测试扬声器的音调的工具),使用 /dev/snd共享:
docker run --rm \
-i -t \
--device /dev/snd \
docker-device-example \
speaker-test

问题

运行上一条命令时,会播放粉红噪音,但 仅在某些情况下 :
  • 如果我没有在主机上播放任何声音:例如,如果我正在播放视频,并且即使视频暂停,命令也会失败
  • 如果我没有运行另一个访问 /dev/snd 的容器设备

  • 它看起来像 /dev/snd使用时被“锁定”,如果是这种情况,我得到以下输出(错误由最后两行表示):
    speaker-test 1.1.6

    Playback device is default
    Stream parameters are 48000Hz, S16_LE, 1 channels
    Using 16 octaves of pink noise
    ALSA lib pcm_dmix.c:1099:(snd_pcm_dmix_open) unable to open slave
    Playback open error: -16,Device or resource busy

    而且,反之亦然,如果播放粉红噪声(在容器上),那么我无法在我的主机(Ubuntu)上播放任何声音。但是我主机上的命令不会失败并显示相同的消息。相反,主机上的命令(如 aplay test.wav 播放简单的声音)被无限期阻止(即使容器随后关闭)。

    我尝试通过运行 strace aplay test.way 进行调试,并且该命令似乎在 poll 上被阻止系统调用:
    poll([{fd=3, events=POLLIN|POLLERR|POLLNVAL}], 1, 4294967295

    问题

    如何同时播放来自 2 个(或更多)不同容器或来自我的主机和一个容器的声音?

    附加信息

    我用 /dev/snd 重现了这个问题,但不知道在使用其他设备时是否会出现类似的情况,或者只是与声音设备或 alsa有关。 .

    另请注意,当运行多个 speaker-testaplay同时命令和 全部在我的主机上 (不涉及容器),然后播放所有声音。

    最佳答案

    我不知道如何用 ALSA 解决这个问题,但可以提供 2 种可能的方法来使用 pulseaudio。如果这些设置失败,请在镜像中安装 pulseaudio 以确保完成依赖项。

    ALSA 直接访问声音硬件并阻止其他客户端访问它。但是可以设置 ALSA 来服务多个客户。这必须由其他人来回答。可能一些 ALSA dmix plugin 设置是要走的路。

  • 带共享套接字的 Pulseaudio:

  • 创建脉冲音频套接字:
    pactl load-module module-native-protocol-unix socket=/tmp/pulseaudio.socket

    为 pulseaudio 客户端创建 /tmp/pulseaudio.client.conf:
    default-server = unix:/tmp/pulseaudio.socket
    # Prevent a server running in the container
    autospawn = no
    daemon-binary = /bin/true
    # Prevent the use of shared memory
    enable-shm = false

    与 docker 共享套接字和配置文件并设置环境变量 PULSE_SERVERPULSE_COOKIE 。容器用户必须与主机上的用户相同:
    docker run --rm \
    --env PULSE_SERVER=unix:/tmp/pulseaudio.socket \
    --env PULSE_COOKIE=/tmp/pulseaudio.cookie \
    --volume /tmp/pulseaudio.socket:/tmp/pulseaudio.socket \
    --volume /tmp/pulseaudio.client.conf:/etc/pulse/client.conf \
    --user $(id -u):$(id -g) \
    imagename

    cookie 将由 pulseaudio 本身创建。

  • 基于 TCP 的脉冲音频:

  • 从主机获取 IP 地址:
    # either an arbitrary IPv4 address
    Hostip="$(ip -4 -o a | awk '{print $4}' | cut -d/ -f1 | grep -v 127.0.0.1 | head -n1)"

    # or especially IP from docker daemon
    Hostip="$(ip -4 -o a| grep docker0 | awk '{print $4}' | cut -d/ -f1)"

    运行 docker 图像。你需要一个空闲的 TCP 端口,这里使用 34567
    (TCP 端口号必须在 cat /proc/sys/net/ipv4/ip_local_port_range 范围内,并且不得在使用中。检查 ss -nlp | grep 34567 。)
    docker run --rm \
    --name pulsecontainer \
    --env PULSE_SERVER=tcp:$Hostip:34567 \
    imagename

    docker run 获得容器的 IP 之后:
    Containerip="$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' pulsecontainer)"

    加载使用容器 IP 进行身份验证的 pulseaudio TCP 模块:
    pactl load-module module-native-protocol-tcp  port=34567 auth-ip-acl=$Containerip

    请注意,容器启动并运行后会加载 TCP 模块。需要一点时间,pulseaudio 服务器才可用于容器应用程序。
    如果 TCP 连接失败,请检查 iptablesufw 设置。

    总结这些设置的方法: https://github.com/mviereck/x11docker/wiki/Container-sound:-ALSA-or-Pulseaudio

    关于 docker : sharing/dev/snd on multiple containers leads to "device or resource busy",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51859636/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com