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

标签 docker alsa

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/

    相关文章:

    spring - Docker:客户端和服务器之间的链接

    linux - 多线程游戏程序突然锁定在glXSwapBuffers上

    c++ - 我可以从内部暂停回调吗?

    c - 如何处理错误: expected expression before ‘do’ when there is no “do” ?

    Docker 上的 Oracle::ORA-12162: TNS:net 服务名称指定不正确

    node.js - 如何在docker中创建live-reload开发环境? (NodeJS、Redis 和 Vue)

    typescript - 尝试在Dockerfile中编译TypeScript文件失败

    java - 在单独的机器上运行 bazel 远程执行程序测试

    linux - Linux 中的实时音频分析

    c - snd_pcm_writei 延迟后不工作